summaryrefslogtreecommitdiff
path: root/python/helpers/pydev
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2014-05-28 17:06:51 -0700
committerTor Norbye <tnorbye@google.com>2014-05-28 17:06:55 -0700
commitc667c1f74abd96a2098520effdd5afdff7f0d34b (patch)
treeab650b0e69fb57d40350579d8796da74d8ea49cb /python/helpers/pydev
parent0f831a730c50607e2ffd95020875af6185e17734 (diff)
downloadidea-c667c1f74abd96a2098520effdd5afdff7f0d34b.tar.gz
Snapshot idea/138.343 from git://git.jetbrains.org/idea/community.git
363dc51: row color for byte code viewer under darcula 98900f0: external annotations markers: move to fast line markers d5ee2ec: testdata fixed 2780ae5: ensure test class writable b8cdda6: preserve read-only status for class to test 27c5938: test generation: accept same test class name; avoid same test names 55c4e7a: Merge remote-tracking branch 'origin/master' 81c6fb5: PY-11592 Django 1.6: TEMPLATE_DIRS variable in settings.py is not created properly on project creation d4a3220: SQL: per-statement file structure grouping 3f7f1c1: IDEA-125397 Cyclic Expand Word no longer completes numbers 1443a9f: IDEA-125137 Click on failed unit test console output to navigate to test fails when using Groovy test name with '()' in test method name bb1b109: Merge branch 'master' of git.labs.intellij.net:idea/community d92b567: doesn't show empty langs in postfix completion tree 6252558: IDEA-88175 (wrong inspection Contents of collection 'x' are updated, but never queried) 5298c6b: HgCommandExecutor refactoring d215ac2: identify command from WorkingCopy changed to local 3dcf8ce: Merge remote-tracking branch 'origin/master' 8199a13: CCE 1cd6faa: Merge branch 'master' of git.labs.intellij.net:idea/community b2f594a: Merge remote-tracking branch 'origin/master' c2ad3ae: IDEA-119640 Problem with goto declaration of XML attribute defined in XSD 701f9fb: Merge branch 'master' of git.labs.intellij.net:idea/community fada6f1: Add temporary api to allow custom initialization of debug session data a41ecf9: IDEA-123466 Sheet dialogs doesn't transfer focus back then closed ea02814: Merge branch 'master' of git.labs.intellij.net:idea/community c6be0ae: XBreakpointUtil.getShortText() shortens text now 740b6b1: [log] IDEA-125578 Handle empty permanent graph d0891b3: IDEA-125580 - OpenShift: cloning application hangs if switch to another process 11202b9: DevKit: Goto EP declaration in plugin.xml (IDEA-86100) 8ebe9dd: IDEA-125258 ("Unnecessary boxing" inspection is triggered wrongly with overloaded constructors) 55ba38d: IDEA-121467 Quickfix inserts static imports instead of plain imports for inner classes 978a1dc: try with default pattern provider if selected one was not found (IDEA-125581) 8a80f67: leave foreign params untouched (IDEA-119700) 6c8c34c: avoid assert on IDE close with active debug session c68b3d3: IDEA-125344 (Serializable class without 'read/writeObject()' inspection should ignore classes w/o additions fields) ce6deee: IDEA-125558 new debugger: double result in evaluate expression 0315d6f: Merge branch 'svn_18_3' 7dcc19e: fix expression name for postfix template 2c9f426: [meo] restore backward compatibility in single-element CompositeFilter merge a6f23d0: use NavigationGutterIconBuilder 4ab120e: Merge remote-tracking branch 'origin/master' 1c6bfe0: invoke 'install plugin from disk' action from ctrl+shit+a a345e24: IDEA-125542 new debugger: 'rerun' failed tests are lost 53fd954: IDEA-125542 new debugger: 'rerun' failed tests are lost c9716a4: IDEA-124891 Implementation icon in gutter overlaps preview for Icon class Get rid of icons from collapsed areas f54e61d: ObjectsConvertor cleanup 05b53b7: IDEA-125421 diff tool opens wrong file if VCS file deleted via file system 854abe7: + retina variant 0d0dc51: add new icon 2e35935: broken plugins added ad666ec: do not bother users with warnings from external annotation roots 32fe274: stream api: do not collapse loops when body is not throws compatible (IDEA-125541) 972c75d: Lazy load the icon in DependencyValidationManagerImpl. #188 775e4cc: IDEA-124609 Unexpected indentation of anonymous classes 41c5b88: save caret position in evaluation dialog 4ca7c2b: cleanup 5287678: cleanup 7984ec9: IDEA-122538 Implemented "repository supports merge tracking" detection (for both command line and SVNKit) ffbcd16: fixed debugger tests 3d12351: disable postfix templates for coffeescript bfd4b28: ExtendedBuildModel now exposes the project's build directory. 9786fa2: fixing debugger tests 13e4b01: make test light ad7096e: IDEA-125361 (False positive 'Field may be final') 8ef32c8: missing dep e62c3c5: Merge remote-tracking branch 'origin/master' 895353f: extract DevKitGutterTargetsChecker 5c120d4: goto actions: vk_up/vk_down fix [^vasya] 2750009: Merge remote-tracking branch 'origin/master' 5859ed9: IDEA-125486 (Comparison using == instead of .equals() should replace with Objects.equals() instead of the instance .equals() method) 1316de2: PyCharm 3.4 artwork. 03da78e: Merge remote-tracking branch 'origin/master' 0cb2b06: Merge remote-tracking branch 'origin/master' a6d22de: fix testdata; restore again ExpectedHighlightingData 40420a0: quote parameters if win command processor launched with extra switches (e.g. /D) b61f519: Merge remote-tracking branch 'origin/master' f587cf6: require less stack in ResolveClassTest.testStaticImportNetwork 13441f9: Merge remote-tracking branch 'origin/master' 892e199: fix test 6c56888: Merge remote-tracking branch 'origin/master' 1d8d3f1: lambda: ignore results of assignment is used for expression lambda (IDEA-125473) eaa9ce6: method refs: check if interface functional (IDEA-125511) 5e7d32c: edit sources for documentation component; F4 2cf09bb: include window class into diagnostics (met with documentation popup) 2853c95: cleanup code on commit option d2c04b8: anonymous -> lambda: do not collapse to lambda functional interfaces with generics methods, accepted by method refs though c20f9d2: Merge remote-tracking branch 'origin/master' bfc443c: do not visit additional resource roots twice: additional indexed resource root providers can return intersecting paths sometimes 4b7dc58: a less gc-producing ImmutableText.subtext 2dc1af8: optimize ImmutableText memory usage 8dbda1f: [vcs] Log executable validation failure reason 9b3a535: [git] cleanup 52fb0b3: DebugLogConfigureAction: define the default focused component 47956e6: Merge remote-tracking branch 'origin/master' ec369f5: Local History tests tuned for new VFS behavior 6c0132d: Platform: IDEA-125330 Warning about non-project file modification should be merged with Read-only warning and shown in a modal dialog c611e59: Merge remote-tracking branch 'origin/master' b3afb57: Platform: OS X scrollbars can be disabled for diagnostic purpose d300533: Merge remote-tracking branch 'origin/master' a1d5b1c: fix border in dbe table editors 72f2e89: cleanup dccc79d: Merge remote-tracking branch 'origin/master' 5ffae2a: fix class with wrong qname sometimes returned from findClasses 813ab5f: [log] Don't schedule a refresh task if there is nothing to refresh a40d619: [log] Fix IAE when jumping to row #0 in empty table 2d2cf45: [log] set bek synchronously when applying filters to avoid locks 80e3729: Merge remote-tracking branch 'origin/master' c256133: fixed jdi objects leaks c10a0ca: Merge remote-tracking branch 'origin/master' 354d205: Merge branch 'python-fixes' 99c6577: Fixed false positive for 'yield' expressions in lambdas (PY-11663) 5de561b: Fixed false negative for 'yield' expressions in default values of parameters e23c4c0: Cleanup 222ecc2: hide execute in console action if not available a9d038d: Merge remote-tracking branch 'origin/master' 6823565: Merge remote-tracking branch 'origin/master' 26a710e: Merge branch 'modulefileinex-service' of https://github.com/yole/intellij-community into yole-modulefileinex-service 4be8c9b: Convert ModuleFileIndex to a module-level service. b37122b: merge hyperlink merging changes by meo (https://github.com/JetBrains/intellij-community/pull/185); cleanup 68f7fad: IDEA-125248 Incorrect simplify for float c82e10f: Merge remote-tracking branch 'origin/master' b7c5190: IDEA-125357 Throwable at com.intellij.openapi.wm.impl.WindowManagerImpl.isAlphaModeEnabled(WindowManagerImpl.java:359) 5e0039e: Merge remote-tracking branch 'origin/master' e32d36a: path fixed 9989bd2: Merge remote-tracking branch 'origin/master' ec32500: new "Serializable object implicitly stores non-Serializable object" inspection IDEA-62336 9db4420: - switching data buffering only once per state change - upon before file deletion event remove the file from myFilesToUpdate - rename inner class and other cleanup 438a3e2: final in "foreach" loop 0c86e1e: default message for postfix templates e8cef21: Merge remote-tracking branch 'origin/master' e2a7723: don't access disposed excluded entry (IDEA-120622 workaround) 33929c5: don't use checker.xml for dfa (but leave it there for a while, IDEA-125426) d50f08a: Merge remote-tracking branch 'origin/master' 7f8eae7: unification example postifx templates 45a21b2: Merge remote-tracking branch 'origin/master' 0fcb1c3: introduced pycharm_load_entry_point instead of searching for executable through local file system 76c0e94: moved inspections to groovy-psi 7c078e9: path to standardDsls fixed 1e4a913: moved more stuff to groovy-psi 0c48aca: DevKit: ExtensionPointCandidate: target PsiElement, EP-Locator: performance, search without supers 9dd16ef: Merge remote-tracking branch 'origin/master' 1a0533b: Merge remote-tracking branch 'origin/master' e617070: reverted 47fc79d09ef2793cd5fcc468d1fe7454bc5e4265 0375c72: correctly render more collections elements a149338: rearrange actions and added separators in context menus 0e230ea: fixed PY-12970 Extract variable: disable refactoring for parts of comrehensions 4af130d: use IntObjectMap in DirectoryIndex to avoid holding VirtualFile objects e41dedc: faster AdditionalIndexableFileSet.isInSet bb13e6f: Merge remote-tracking branch 'origin/master' f293b00: invalidate cashes stats 8173bf0: app start stats 1578ddf: JavaRearranger: proper processing of anonymous classes. 5580933: DevKit: extract ExtensionPointLocator 42702c9: moved to core ee9fcba: moved ExpressionConverter to psi 8404532: add groovy-psi to the roots for standardDsls loading e61091e: moved to psi f84bdce: export dependency 8c3458e: moved to properties psi 8a342ab: moved to core 0cf35f7: resource/gen ac478b1: moved resources to groovy-psi, regenerated icons 18ab45e: moved to core 1991ad8: moved to psi dc90b9a: cleanup cc0fbf8: test fix 9ed02a6: Platform: IDEA-125277 provide extension to allow non-project file modifications without notifications 817df5b: return code in django_manage_shell for old django versions 2355467: fix django console for PY-13031 remove old code with execute_manager and setup_environ fix django prompt 7b308ab: EA-54820 - assert: ClassMappingNameConverter.getVariants: fixed fd94f78: EA-54820 - assert: ClassMappingNameConverter.getVariants: diagnostics d0c1508: syncronize 'assert' c1ec45d: toString() restored 8142475: replace assertSame with assertEquals when comparing virtualFiles 9ee6a48: IDEA-123484: generate stub type definition for implicit trait type mixing a4094bf: IDEA-123484: multi-trait type dff7733: IDEA-123484: as operator with traits 0eefe8c: IDEA-124932 "Analyze Backward Dependencies" on any class fails with AssertionError: diagnostics d133496: javadoc 03ffdcf: IDEA-118036 Exception editing JSP file: diagnostics 49d5445: escaping redone, now only for double quotes cdca783: GPUB: drop deprecated stuff, parseTokenSmart & cleanup 6aef47f: Merge remote-tracking branch 'origin/master' d001816: PY-12734 Templates in app directories not found with implicit TEMPLATE_LOADERS 4fa70d5: do not write new setting to profile if it has not changed from the default value d38e995: fix for private fields 6e3b903: cleanup ProjectView popup menu and EA-56883 on Java8 a8ca529: Merge remote-tracking branch 'origin/master' f8b1755: revert: make too many mess in testdata to have everything escaped in error messages; or we won't have an ability just to accept actual error message and would have to rewrite it manually 6d3bf6d: IDEA-125464 Non-pinned and non-docked tool windows do not hide anymore f6a8a5e: (IDEA-89870, IDEA-114058) hg4idea: java.lang.AssertionError: Invalid command 51a5628: make exception dialog appear faster for long traces ea09e6e: don't fire UseVirtualFileEqualsInspection on comparisons with this 506a2cb: include anonym prefix in internal canonical text to avoid incompatibility messages with "same" types on both sides 5953b8f: accessibility of private method via anonymous classes fixed e43dbe0: IDEA-122430 Search in class hierarchy: preselect class b290c14: IDEA-125430 do not clear package view attributes a4898d7: Utility method for text alignment ee26a53: [log] Add registry key vcs.log.bek.sort=false. 2147279: [log] Add bek button. 02e5afb: [log] Add GitBekParentFixer for GitLogProvider. 9774870: [log] Create BekSorter. e3177e8: [log] Fix DelegateGraphFacade when applying filters. 56c0dd0: [log] fix VcsLogColorManagerImpl. 313c4b1: [git] cleanup: move method to the only place in tests where it is used a981a80: [git] IDEA-125328 Don't crash if commit/author time is empty a0f6188: Merge branch 'python-fixes' f0bc595: Specify HTTP URL scheme for proxy string passed to 'pip' (PY-12771) 843daaa: IDEA-125237 part II, the considering of static final fields 9213ca5: [log] IDEA-125309 One more fix for a possible deadlock f4b288b: fix gray gap in ComboBox under Darcula and IntelliJ lafs bdeea08: fix java.lang.IllegalArgumentException: Row index out of range when history is empty b553f5c: check for plugin incompatibilities before update for a new version (IDEA-24014) 1fc11e7: cleanup f6f7050: Merge remote-tracking branch 'origin/master' dc5157d: Fix CME in terminal (IDEA-125398). d8b5ecb: IDEA-125378 SQL: Implement keyword-based operators completion d591ab2: IDEA-107350 EvaluateXPath dialog: input field height is too small, text is unreadable 033aed0: IDEA-91663 (Method can be variable arity method shall have an option to ignore methods with multiple array arguments) 2335b92: make test light f0fdc59: IDEA-124590 Java Rearranger: Implement "section" support 61b6ca0: icon class regenerated 67b1070: Merge remote-tracking branch 'origin/master' ce11bc5: Merge remote-tracking branch 'origin/master' 3501998: PY-13018 ForeignKey to model in different file brakes backward references if referenced as APP_NAME.Model 383494f: Package info with links to confluence added 961bf42: Start plugins wizard #29 move plugins saving to beforeOkAction 42c25f2: DevKit: resources, icons, DevKitBundle 36d20ee: fix wrong LAF shown in Settings/Appearance on first run 86cda23: do not show empty Refactoring popup group aa68afd: IDEA-124119 [regression] Breakpoints dialog: checkbox for "condition" field is gone 544238b: Don't draw terminal content out of the terminal panel component (IDEA-125317). fdf377f: Merge remote-tracking branch 'origin/master' 9f9e67e: Don't draw terminal content out of the terminal panel component (IDEA-125317). 635cfcc: show renderer's icon in variables view a44cf2c: Merge remote-tracking branch 'origin/master' 70e83b9: Fixed scrolling issue in terminal (IDEA-125223). 947ef5c: show number of recurrent call in stack frames list a092c29: optimization: avoid unnecessary disk access operations 09d7890: Revert "Fix list selection background when unfocused" 15b772c: rerun browser on performed fix c7d2582: an internal inspection checking that virtual files are compared with "equals" d763d57: PushedFilePropertiesUpdater: don't start dumb mode because of vfs changes outside the project 844d483: compare virtual files by equals, not == b9b3b32: cleanup 82c9f72: cosmetics a8adf75: continue "auto expressions in Coffee" spec 00e17e3: borders for IntelliJ LaF 5857e85: removed another copy of processing files with given set of data keys 782f5eb: Merge remote-tracking branch 'origin/master' 164f48e: make customizable 9fe0fda: jediterm updated to fix IDEA-125385 421f658: selection border 356ac7a: default table render offset 5854fc8: support empty borders 92226c5: Merge remote-tracking branch 'origin/master' e3e854a: IDEA-125287 [new Java debugger] trimmed string value in Variables view f2f3a64: project file conversion: API, @NotNull and javadocs 96a6ad6: IDEA-121475 Row height in "Environment Variables" too low 19e6f54: IDEA-125369 (Error highlighting remains after expanding annotation to normal form) 3a80bec: IDEA-121475 Row height in "Environment Variables" too low After-review rollback 757fb8d: heads, parents and several other mercurial commands should be executed as local commands 6bb121c: IDEA-64250 ("simplifiable annotation" inspection could unwrap single-element array arguments) 54fdb56: [log] IDEA-125309 Fix deadlock. invokeLater instead of Wait 59630f4: Merge remote-tracking branch 'origin/master' cc055ad: fixed PY-12405 --noinput option does not work when running django unit tests 22b7cde: IDEA-122962 - Clouds: perform connection test in background - fix UI breaking on long error message eb65298: IDEA-125287 [new Java debugger] trimmed string value in Variables view ee02141: sources roots without sources converted to resource roots f2d9cda: @Nullable 2c2bc76: remove hardcoded RED color in tooltips 16d79c0: add module dependency [debugger-impl] -> [util] 2ff22a8: fix focus border around selected elements fabedf6: for indexed refactoring d4d6b60: sources roots without sources converted to resource roots 09c92d9: invalid source roots removed d750e35: XDebugger: Added myCustomTopPropertiesPanelWrapper to XLightBreakpointPropertiesPanel a1a393b: IDEA-124402 Exception during choosing input XML file 07e7838: IDEA-125289 Unexpected navigation after folding After-review fix 903857f: write action 268b90e: IDEA-124119 [regression] Breakpoints dialog: checkbox for "condition" field is gone - added mnemonic 2b3c1e1: notnull 2df4494: moved to psi a708897: notnull 90859a3: moved to psi a50eb7d: moved to psi, reduce dependencies 0a59e6f: notnull 76b18d8: moved to core 27e528f: continue "auto expressions in Coffee" spec fix NPE - absoluteLocalPathToSourceIndex 8a7ce9b: ensure fonts are not lost during collapse/expand, second popup shown, etc 0282f9e: IDEA-125047 Wrong error in XSLT injection d8f9f2b: Merge remote-tracking branch 'origin/master' 3baeea4: try to highlight only wrong argument in inapplicable call 607732e: ensure scrolling finished before popup is shown 7e77395: include build target info in error message for unexpected errors 1676779: IDEA-123049 Rearrange Code is breaking code (Code Style > Java > Arrangement) f91bf07: capitalization corrected 8f14954: IDEA-125302: The Analyze Stacktrace menu option remembers only one log file across multiple projects 7520a18: notnullification 94e42a8: don't warn on annotations containing errors 90a4b5c: make test light b2fc5b1: allow xml escaping in test highlighting data 3794f56: Merge remote-tracking branch 'origin/master' 68565ae: PY-2980 Unresolved reference for ForeignKey defined as string d923e07: IDEA-122956 Popups in Project Structure dialog have wrong initial size sometimes 202643b: init "auto expressions in Coffee" spec a23319a: cleanup 552c2c5: cleanup cb9b56b: cleanup b719055: Merge remote-tracking branch 'origin/master' 67ec3fc: IDEA-125269 List: bad selection BG/FG color cfa83df: use JBColor cb3f677: use default color scheme if using darcula color scheme with default LAF 1b9cdd8: get rid of unused DirectoryInfo.orderEntries field dd3c283: IDEA-124793 Editor gutter background not painted, gutter icons displaced 9f9a8b5: IDEA-121475 Row height in "Environment Variables" too low 98c8696: apply code cleanup after code generation, let's see how it would work on the long run (IDEA-124904) 7c15dce: cleanup tools extended a915a2d: update editor notifications on roots changed c21f106: check app directory first (IDEA-125294) c731f05: bomb test 9424172: Merge remote-tracking branch 'origin/master' 61fd17b: IDEA-125189 new debugger: pause doesn't select thread in frames combo c4f4f08: IDEA 123484: fix test ba16a8c: move all header into starting script for django console (PY-11728) dbe0fc8: IDEA-121687 New module->Ruby on Rails doesn't allow to specify sdk IDEA-121685 New module->Ruby has confusing UI 6db5e53: HgCommandExecutor refactoring (IDEA-119330 Reorganize mercurial command execution ) 3066cd3: IDEA-124119 [regression] Breakpoints dialog: checkbox for "condition" field is gone fbdaf43: foreach simplification + for in js postfix template 77e2c15: ignore 'winShellScriptingQuoting' test if not Windows 77df25e: AnnotateStackTraceAction in now reusable a1b2bed: Merge remote-tracking branch 'origin/master' cb8a9f0: add module dependencies: do not show duplicates (IDEA-125033) f5656e8: gutter icon for external annotations (IDEA-39633) bb5631c: action to change assignable var type (IDEA-125234) ec9a61b: extract method: redundant cast treatments (IDEA-125259) 68f0af6: IDEA-125262 Can't create Django, AppEngine and other specific Python projects 6ebbcc6: cleanup e11cf17: introduce process queue to auto-clean tossed resolve results 1a6a08f: compilation 2855b05: groovy sucks 11ba843: moved to psi 726502f: moved to psi 9fdcc12: removed static interface inheritance to reduce unnecessary dependencies 77522ae: inline GroovyFileType.GROOVY_LANGUAGE a093f0d: introduce groovy-psi module 65b4b98: moved to ui-ex 4f7b33b: CopyPastePostProcessor interface converted to class so incompatible plugins won't break copy-paste functionality (and exception will be shown only on first invocation) c946899: removed unused action to lessen dependency lang-impl on vcs-impl 0cb7117: removed unused code to get rid of dependencies from lang-impl to vcs-impl 68c8c32: some dependencies from lang-impl to vcs-impl removed a61b41f: IDEA 123484: support for trait fields. Accessors and pack__name fields abe983d: IDEA 123484: get rid of PsiImplUtil.isTrait(PsiClass) 98777dd: Gradle: nonclasspath finder updated to search psi classes in groovy sources 50c85d4: OC-9949 Breakpoint editing popup layout is broken e7884cc: vcs specific classes moved from lang-impl to vcs-impl 47fc79d: PY-12810 "imported" urls are not supported by {% url %} tag ( "patterns +=" now supported) 535e2f3: svn: Refactored SvnConfigureProxiesDialog - execute "svn info" as "test connection" implementation (instead of direct SVNRepository usage) 4c22b04: svn: Refactored BranchMerger - get latest source revision using InfoClient (instead of direct SVNRepository usage) 2046a89: svn: Refactored SvnUpdateEnvironment - get latest repository revision using InfoClient (instead of direct SVNRepository usage) f024c0c: svn: Refactored SvnUpdateEnvironment - removed unnecessary parameters, code simplified 39e5d54: svn: Fixed LatestExistentSearcher - ensure repository relative url starts with slash (for correct relative urls comparison) 65370cd: svn: Refactored LatestExistentSearcher - get latest repository revision using InfoClient (instead of direct SVNRepository usage) 6c0f1f1: svn: Refactored LatestExistentSearcher - fixed warnings, rewritten recursion with while loop d4fd095: IDEA-125237 (Misordered 'assertEquals()' arguments: support non-primitives) a11c2bd: svn: Refactored LatestExistentSearcher - check if item exists in given revision using InfoClient (instead of direct SVNRepository usage) 957aebe: svn: Refactored LatestExistentSearcher - use repository url passed as parameter (and not resolve repository url by itself) a4fcdde: IDEA-125289 Unexpected navigation after folding 894bbbd: fixed no toString value 8168063: replace @Nullable findInstance with @NotNull utility with logging (EA-55734) 061c4b0: compilation fixed: use dependency on 'annotations' module instead of 'annotations.jar' a454164: style 30287ac: IDEA-125285, EA-645852: AppCode exception on start up +review c08b9bd: Merge remote-tracking branch 'origin/master' 546f5fd: IDEA-86100 DevKit: support "Go To Related File..." sort after/before template files f4d0b25: svn: Refactored SvnUtil.remoteFolderIsEmpty - check folder content using BrowseClient (instead of direct SVNRepository usage) 12a5319: tweak insents 0e3c26e: [log] allow more results for the first request to get filtered results 06aebe0: Emmet: remove redundant borders from preview 2012b06: IDEA 123484: clashing methods from super-traits. Prefer the method from the last trait 1ba5924: IDEA 123484: access to super method with super. qualifier 205f80d: IDEA-124891 Implementation icon in gutter overlaps preview for Icon class c17387a: IDEA-86100 DevKit: support "Go To Related File..." 298ee51: Merge remote-tracking branch 'origin/master' 3c638cb: show variable name for arg_x and slot_x variables 3280f4f: [log] LOG.info the ISE (Joiner failure), not LOG.error f2e2a1b: [log] Joiner: use THashSet with much faster removeAll a32815c: [log] clear IntStack in DfsUtil. a5380f0: [log] Optimize IntTimestampGetter. bba2e43: [log] Optimize PermanentGraphImpl#getAllCommits() 02daba7: [log] Move GraphCommit implementation to vcs-log-graph 13378bb: [log] Add vcs-log-graph-api to root build modules 057c82c: fix author width update a1fe976: [log] Rewrite the process of refreshing log & building the DataPack 5cffaba: [log] Add sort type to PermanentGraph#createVisibleGraph. 081b82e: [log] Fix arrow. fa93a67: [log] Fix edges sort problem. 42874b2: [log] Create SmartDeltaCompressor. 89d784b: [log] Create new PermanentListIntToIntMap. It is useful for IntDeltaCompressor. a4141ad: [log] Fix NOT_LOAD_COMMIT. 82f85bd: [log] Fix color id. de26777: [log] Extract GraphLayoutImpl from GraphLayoutBuilder. 1b43a23: [log] Add DelegatedPermanentGraphInfo. 50b2fc4: [log] Create PermanentGraphInfo & PermanentCommitsInfo. 3cd6eb1: [log] performance fix. f5413a0: [log] PermanentGraphBuilderImpl - initial version 9210824: [log] Always request ordered recent commits c4804c2: [log] move getFilteredDetails to VcsLogFilterer 63b4315: [log] use interface 2ca8eac: [log] Remove obsolete ContentRevisionFactory ef6d65e: [log] Add new vcs-log-graph-api module in ultimate dd97706: [log] Fix jump to not load commit. 0510209: [log] Use trove HashMap. 8476e99: [log] Optimize in PermanentCommitsInfo for case CommitId == Integer. 3b585f0: [log] optimize full graph build. 2441f57: [log] Generify VcsLogJoiner. 954a4c2: [log] Fix mouse over action. 44505e8: [log] add equals & hashcode for PrintElement. 5d94e56: [log] Collapse all. 64433f9: [log] Fix oneOfHead(). 50388d4: [log] fix CurrentBranches. 24275af: [log] Fix CollapsedVisibleGraph. e86fb65: [log] performance problem 20b21f2: [log] Fix with for graph cell. 108183c: [log] Fix EdgesInRowGenerator. 4cc1adc: [log] Fix underdone nodes. e34b093: [log] Fix colorId. af5b227: [log] Drop VcsCommit. 616274e: [log] COMPILED! 4211697: [log] fix DataPack 3cbb213: [log] Change signature of GraphFacade#getAllCommits(); 545ef9f: [log] Rename getTime() -> getTimestamp(). 6fbc6f6: [log] Rename getHash() -> getId(). 33a7f03: [log] compilation fix. 4cb058c: ~~ [log] Add module dependence. bc7a666: [log] Add DelegateGraphFacade. b3d2206: [log] Add getVisibleRowIndex to VisibleGraph. 0a77ab3: [log] Make FilterVisibleGraph. c9795ab: [log] Make CollapsedVisibleGraph. 5be555e: [log] optimize import. 6650399: [log] Add branchNodeIndexes in PermanentGraphImpl. 293ef9a: [log] Add constructor. 15dd5b1: [log] Add IdFlags. 34c687e: [log] Fix PermanentGraphImpl. a4c2797: [log] Move method from CollapsedVisibleGraph to AbstractVisibleGraph. e671eb1: Extract deprecation warnings only if they present in text. b30e3f0: [log] In GraphColorManager JBColor -> int(colorId) && int -> CommitId 340ba68: [log] Fix EdgesInRowGenerator and add several tests. 1ec4cda: [log] Add LinearGraphWithElementsInfoParser. e3369e2: [log] Remove unnecessary BufferedReader usage. bd18165: [log] Remake test package structure. 4a67d5e: [log] Fix equals fox CommitId. 408d6878: [log] Remake tests. 62cad84: [log] Small fix. 88e5afd: [log] Remove newgraph package. c3fbf99: [log] Add Flags#setAll(). b8c1375: [log] Move DfsUtil. 770aff8: [log] Remake image printer. b49cea0: [log] Remake PrintElementsManagerImpl. 97c5f6d: [log] Add AbstractPrintElementsManager. fe3a680: [log] Create new PrintElementWithGraphElement. 80d21e9: [log] Remake ContainingBranchesGetter. 5996a24: [log] GraphCellGeneratorImpl -> PrintElementGeneratorImpl. 6b56353: [log] Generate equals & hashcode methods. 55b4219: [log] Remake AbstractPrintElementGenerator. 938956f: [log] Add simple implementation of PrintElements. 3784b45: [log] Remake EdgesInRowGenerator. ad7d357: [log] Remake FragmentGenerator. 1a1d238: [log] Add draft of CollapsedVisibleGraph. 95a51cd: [log] Add AbstractVisibleGraph. b8a9f02: [log] Fix CurrentBranches. 8722519: [log] PrintedLinearGraph.getLayoutIndex() -> getGraphLayout(). f6467e4: [log] Add draft files for PrintElementGenerator. 6f8ff22: [log] Add FilterGraphWithHiddenNodes. 6563dea: [log] Some changes in CollapsedGraphWithHiddenNodes. 0994121: [log] Add constructor. ad25cff: [log] Remake GraphWithElementsInfoImpl to CollapsedGraphWithHiddenNodes. 3abc13e: [log] Extract inner class. c9a5fb2: [log] Add LinearGraphAsGraphWithHiddenNodes. 3b2baa1: [log] Fix update event in GraphWithHiddenNodesAsPrintedGraph. a9bee1b: [log] graph.impl.visible.utils -> graph.impl.visible.adapters 2f4b46f: [log] Move all from vcs.log.facade.utils -> vcs.log.graph.utils. 579ee01c: [log] PermanentGraphLayout -> GraphLayout. 8e14dd2: [log] Add draft of PermanentGraphImpl. 6e5d35f: [log] Remake PermanentGraphBuilder to PermanentLinearGraphBuilder with CommitId. 313093e: [log] Remake PermanentCommitsInfo with CommitId. 8151d60: [log] Create new internal graph api. 797b59b: [log] Add PermanentCommitsInfo. 5e909f3: [log] Add IntTimestampGetter. 5049be6: [log] Drop unnecessary method from PermanentGraphLayout. adfa4b0: [log] DfsUtil: use IntStack. 24768a4: [log-api] Update api. b02fc19: [log-api] Update api. d1fce17: GRAPH API e7526b1: svn: Refactored BranchMerger - removed unused fields/parameters 65bab47: DevKit: refactor InspectionDescriptionNotFoundInspection 5a18a7e: svn: Refactored SelectLocationDialog - get repository root url using InfoClient (instead of direct SVNRepository usage) caa8262: support ContinuationWebSocketFrame cf56368: Calculate future feature only if it present in text. 1a79f0f: svn: Refactored SelectLocationDialog - removed unused code, removed duplication 445763e: do not calculate mirror file for each access to jar file 5cfdfeb: fix IllegalArgumentException: The file: doesn't exist. 49b2232: AC/C++: EA-56192 only allow directories in NullFileReferenceHelper roots +review CR-OC-1544 30d5ad4: js postfix template: parenthesized 3ce7f95: quote param containing ampersand for .bat files 0008feb: Based on comments for http://crucible.labs.intellij.net/cru/CR-IC-5400 * quote param containing ampersand for .bat exe files * improve test to actually execute .cmd/.bat files 2fb4ba8: reverted 69ea226: custom strategy bug fix, new Weak key soft value map e7ed4bf: moved to ui-ex bc74ad3: moved to core-impl c2083de: [log] Handle the case when null value is passed to the renderer 86c197a: IDEA-125227 New debugger: please disable switch from expression mode to code fragment mode when evaluating multiline expressions 519d350: Gradle: discover local gradle sdk sources local gradle dependencies 911aa11: inline GroovyFileType.GROOVY_LANGUAGE 9668cc5: renamed 06ad15b: javadoc, IncorrectOperationException replaced with UnsupportedOperationException as more standard 940d174: javadoc, cleanup, removed bulk operations since they are not jdk8 compatible anyway 7e1f445: AC/C++: EA-56192 allow files in NullFileReferenceHelper roots +review CR-OC-1544 ce9a38c: fixed "unmute on stop" action 2ca53a3: Calculate dunderAll in stubs only if file text contains __all__. 80cb0da: fixed PY-12970 Extract variable: disable refactoring for parts of comrehensions 1fe1440: typo 317cd70: fixed tomcat tests 47060bb: Merge remote-tracking branch 'origin/master' f343aa2: simplification postfix template fb45e36: Gradle: nonclasspath finder updated to search psi classes in groovy sources 897595c: Gradle: EA-54734 - assert: JavaSourceFilterScope.<init> 58d3c58: Gradle: EA-56552 - assert: NonClasspathClassFinder.findClass 3003df2: change class signature: process diamond (IDEA-125236) 479578f: move edit settings down 0da1a20: ensure expression valid, initializer expression should be already replaced (IDEA-125231) 57fa2db: fix tests 30d1d10: select and scroll to most recent revision (IDEA-60345) e54ffc6: scroll tree view file history to most recent change c3d8951: make scroll to selection in file history work better 90de406: support content loading for resource files from output roots (needed by some annotation processors) 6faa3ff: remove unnecessary addClass() calls 113323e: doc test: assert HTML body text only 96d93a8: add new not expression test c7ce438: cleanup 78a4030: Merge remote-tracking branch 'origin/master' 57f67f8: IDEA-125184 Mac launcher should not crash when IDEA_JDK env. var. does not correspond with JVMVersion from Info.plist. e7a2262: js postfix templates: not expression 7877bab: IDEA-125129 I would like to reopen IDEA-117698 3b26929: move jql lexer to gen source root 6723047: postfix template: js introduce variable be8ee4f: refactor expression postfix template with chooser cae5144: cache ClasspathCache.transformName 4119688: javadoc typos d12d8bd: [log] IDEA-116867 Use the same root renderer for author as for message ee1a2cf: IDEA 123484: traits are supported only since 2.3 version 86ffe87: IDEA 123484: complete trait keyword and extends/implements lists in traits 91875b6: IDEA 123484: trait methods are not allowed to be protected 5462267: IDEA 123484: clena up utils and tests 4e540d4: use previously calculated data from PHM if no read right now is performed: calculate the value instead of wait for IO to complete 53e5113: cvs file history in Browse CVS Repository 727804a: AC/C++: EA-56794 - assert: FileReferenceSet.getAbsoluteTopLevelDirLocations +review CR-OC 3326c46: cache already checked plugins (IDEA-124828) 0f9f39d: auto expressions spec: done duplication check 5d4a66c: auto expressions spec: init duplication check 901d664: Merge branch 'github-theme' f55b604: Updated JavaScript and CoffeeScript colors 9c26625: Updated Buildout, GQL, ReST and YAML colors 2bc7a23: Updated Django and Mako templates colors a027a36: Updated CSS, LESS and SASS colors f1a44bc: revert couple, 135 compatibility 8d2b706: change method return type on call site (IDEA-125166) 3316081: Updated HTML and XML colors e4bbd52: move diff utility classes to Util module 54754f3: add evaluate expression action to variable's context menu f915ea5: fixed NPE in evaluate handler 954f437: Updated default colors and set many Python styles to inherited 6c992e4: fix compilation ae76055: Fix list selection background when unfocused 98f8e9f: don't highlight if psi was invalidated (EA-56385 - PIEAE: PsiUtilCore.ensureValid) 9c76516: prevent SOE when creating PIEAE (EA-56284, EA-56810, EA-56809) 968779e: IDEA-123484: override/implement actions are aware of traits 1f6e60a: IDEA-123484: trait -> type_definitions token set c4764e6: IDEA-123484: use newHashSet(map()) instead of map2Set(), import static ContainerUtil.* ae3fce2: Sorted options 08ce945: svn: When looking for cached credentials for given url/realm check also if there are cached credentials for its parent urls/realms (and use them if found) ac6e1c9: IDEA-124077 Enum code reformat destroys enum a92b91b: rearranger @Nullable replacement 1311963: [diff] Simplify the "gear" button implementation e910c1c: fix Cut functionality and tests 9c75b87: [vcs] Simplify the gear action group definition 1dd998d: BlockSupportImpl: assertFileLength2->reportInconsistentLength 57b759f: IDEA-124712 ctrl-alt-space: duplicate completion variants 83a2697: IDEA-125194 Strange control-flow inspection 0f495ff: [git tests] cleanup ce0259e: svn: Refactored RepositoryLoader - use common client factory model (instead of direct SVNRepository usage) d7f2104: WEB-12199 Grunt tool window fails to load Gruntfile tasks, when an "&" is in the path e718569: Merge remote-tracking branch 'origin/master' c8485a5: Merge remote-tracking branch 'origin/master' e79e97b: js potfix templates: notnull & null 2c935f8: [git tests] Fix expected-actual order 81c101c: simplify settings (CR-IC-5127) c061e81: distinguish generated roots during rename/move warnings (IDEA-125147) 61460f7: combine all jdk jars into one marker in OutputChecker b49b8fd: [git tests] Remove a useless blinking test 053f37f: [git tests] Log index.lock error 6616b1a: [git tests] Log debug GitHandler stuff if test failed fed92bd: fixed PY-12991 Missing Added by user mark on paths added to the interpreter abfedef: throw IllegalStateException if number of keys in node to split is different from expected 73218a0: platform: plugin descriptors loading optimized a64c39b: EA-56305 (delegate FS used for parenting) 02521d2: [vcs] Add toolbar to the Shelf d9c049b: [vcs] ShowHideRecycledAction: don't proceed if project is null, cleanup db69de7: svn: Moved several classes to corresponding packages ("org.jetbrains.idea.svn.lowLevel" to "org.jetbrains.idea.svn.svnkit.lowLevel", diff related classes to "org.jetbrains.idea.svn.diff" package) 5546e02: Addede GitHub color scheme fd96e01: fixed tests 9a1a122: Merge remote-tracking branch 'origin/master' 850f818: Revert start_new_thread override. 5c8997d: svn: Refactored RepositoryBrowserDialog.doUnifiedDiff - use common client factory model (instead of direct SVNDiffClient usage) 71d8ba1: svn: Implemented "unified diff" clients (both for command line and SVNKit) e4dc06d: Merge remote-tracking branch 'origin/master' 02a4391: lazy scope initialization in case of big usage view open fba79fe: Slim. Introduce variable test fixed c816eb8: added javadoc d8f4bdd: IDEA-99541 New run configuration type to run Ant get rid of ProcessHandler.waitFor() e3f9e71: javafx: quick fix to switch to javafx css in property starts with -fx-; make css dialects configurable visible when file-mappings are available (IDEA-125020) 3cccccf: file templates: no NPE if exception doesn't contain message 5f0091f: refixed NPE in PasteHandler ea62a1d: NPE in PasteHandler 9ee678f: flusher on low memory should work the same way as periodic memory flusher to avoid loosing updates [r=Eugene.Zhuravlev] 12a7479: Merge remote-tracking branch 'origin/master' 1e48abe: good code red: nested classes inheritance e190be1: fix test 53b9222: processOverlapping should iterate in order cf632d0: do not open API for abuse 7bae702: refactoring - create both RTF and HTML flavours in one copy-paste postprocessor 66d211f: cleanup 4c253dc: refactor API interface 71ea747: make rich copy work for documents with non-normalized line separators c7f67f1: refactoring dc95443: cleanup 74c97e0: remove impact of ADD_IMPORTS_ON_PASTE setting on other copy-paste-related functionality 897f2ba: unused/static imports 873cada: cleanup 5a50486: @Override aa9f4b5: extracted GroovyRunnerPsiUtil f256b8d: moved ErrorUtil to psi 6243ae7: moved GroovyImportHelper to psi 242a795: removed dependency of GrMethodBaseImpl to code style. The clients of GrMethod.setReturnType() should call GrReferenceAdjuster.shortenAllReferenceIn() if they need to 5bdb72f: merged PsiUtil and GroovyPsiUtil f4c8ed4: moved to psi 939b86b: moved method to GroovyPsiUtil 9206109: moved to psi 532fdb0: notnull b6594a3: moved to core 91d1a5b: moved org.jetbrains.plugins.groovy.intentions.utils package to psi 55bb9af: moved to psi b2b65c2: removed dependency on platform 68910bc: moved to psi bda7716: moved to psi 91e946e: moved to core a95cbce: cleanup 7ca3394: cleanup 41b594c: notnull 00f6e5d: correctly identify class usage in dumps 28c6a3c: XML/HTML: move inspection descriptions to proper modules 47f5b9d: Revert "[vcs-log-graph] use Couple" 510ba46: fixed load project test 269e211: Code clean-up. 99f2434: fixed groovy debugger tests a32c4c4: add new test xml map serialization 1b65256: EA-55646: debug output 00964e5: update according to changes in GotoActionModel 9ea4344: rollback 7de12bf: Mono<T> == Function<T, T> 1c4c11b: [svn4idea] use Couple c159007: [testFramework] use Couple 00c700f: [vcs-log-graph] use Couple b8aa01b: [vcs-impl] use Couple 2d2df3b: remove unnecessary static 27c06dd: [ui-designer] use Couple 891b65f: [lvcs-impl] use Couple 9f2118c: [vcs-api] use Couple 31bd437: [properties] use Couple de97b7f: [platform-api] use Couple bbc1d35: [platform-impl] use Couple 7347cd3: [extensions] use Couple fb4d104: [idea-ui] use Couple 756e0ad: [hg4idea] use Couple 5bf1a92: [java-analysis-impl] use Couple ccb6b7c: [java-impl] use Couple c8b9199: [java-indexing-api] use Couple c04909d: [java-psi-api] use Couple d3278e6: [java-psi-impl] use Couple 70fcb07: [javaFx] use Couple eaed3bf: [jetgroovy] use Couple 526441d: [gradle] use Couple 3e1c9d1: [lang-impl] use Couple 7afb583: [dom-openapi] use Couple bffa11b: [debugger-impl] use Couple e9254bf: [github] use Couple 8fc8555: [git4idea] use Couple 187dd78: [vcs-impl] use Couple 2985542: [platform-impl] use Couple 47797e5: [core-impl] use Couple a583560: [core-api] use Couple a8727c8: [compiler-openapi] use Couple 9d30723: [compiler-impl] use Couple 1a54d31: [common-javaFX-plugin] use Couple e25eff2: Merge remote-tracking branch 'origin/master' 3974fdd: Fixed console debug for remote interpreter (PY-12959). db0de10: vfs: .zip file cache reset fixed e677a69: Remove double borders d54e0b0: svn: Refactored RepositoryBrowserDialog.doGraphicalDiff - use correct client factory depending on settings (and not always factory for SVNKit) c7313cf: Merge remote-tracking branch 'origin/master' 18844ff: PY-12810 "imported" urls are not supported by {% url %} tag (fixed quotes trouble) eeab21a: svn: Implemented diff for "url + url" pair for command line 3c6cccf: Data Views specs d47c2cd: EA-56596 - CCE: XmlLanguageInjector$.visitElement 7d729ca: platform: let out/err readers have independent policies e829e8c: store vfs charset in user data 8f05759: IDEA-121961 Debugger: evaluate from variables doesn't include context 0829ee7: better fix for IDEA-125082 90d6990: new inference: separate caching 8148aa2: filter out elements not matching scope (IDEA-125178) b1b6025: extract field from auto closable (IDEA-125141) 827e889: show the notification with a delay to avoid blinking when "too much output" ceases quickly a38bfd3: calculate editor notifications in a single background thread eae74d2: Cache enabling b6b3618: EA-56566 Fix NPE in TaskItemProvider.dispose c77cd7b: Merge remote-tracking branch 'origin/master' 714b3df: fixed PY-12698 Noticeable hang when selecting not yet added virtualenv as project interpreter b44ffe6: EA-56384 Fix NPE in JiraRepository.discoverApiVersion aef1f3e: do not show static node if empty 4c4b111: java-xdebugger: JRuby breakpoints handler a49b8ff: java-xdebugger: fixed tests 31434a5: java-xdebugger: IDEA-125088 Debugger: Evaluate Code Fragment works like Evaluate Expression 11d6bce: java-xdebugger: IDEA-125081 Debugger: Force Step Into works like simple Step Into 7c6f28c: java-xdebugger: allow method calls in quick evaluation with alt 428a04e: use editor font in expression combobox 1b7a152: java-xdebugger: correct context for watches evaluation e4d5f88: java-xdebugger: store java breakpoints in xbreakpoint's user data 3f3fdcd: java-xdebugger: fixes after review a542026: java-xdebugger: use correct context for variables calculation 2a64442: java-xdebugger: IDEA-125035 Debugger: breakpoints: unmute on finish: inconsistencies between behavior and appearance 4f64e19: java-xdebugger: IDEA-125037 Debugger: "Watch method return values" setting label is changed on stop f1de6f7: java-xdebugger: IDEA-125039 Debugger: Throwable at PsiDocumentManagerBase.commitAndRunReadAction() dca55b4: java-xdebugger: IDEA-125038 Debugger: setting field breakpoint causes IAE at SimpleColoredComponent.append() e1a926a: java-xdebugger: IDEA-125044 Debug: Run to Cursor: IAE at XDebugSessionImpl.breakpointReached() c2dc88d: java-xdebugger: fixing tests d369a04: java-xdebugger: avoid assert on context update b53018e: java-xdebugger: fixed breakpoint tests cd4b029: java-xdebugger: no need to recreate java breakpoints dc17bb0: java-xdebugger: do not store empty expressions 36e4354: java-xdebugger: show breakpoint icon when hit for non line breakpoints 9ade5d7: java-xdebugger: add stepping filter action acda84e: java-xdebugger: show extra array elements on demand 563511a: java-xdebugger: no need for extra constant d7a2306: java-xdebugger: correct context for variables calculation 98cb4bd: java-xdebugger: display object id and correct string coloring f882b59: java-xdebugger: show info messages in variables 1d06412: java-xdebugger: show return value on top of variables b1e62e0: java-xdebugger: fixed incorrect frames refresh with enabled filters e86c7d9: java-xdebugger: simplify external breakpoints handlers 764f536: java-xdebugger: fixed exceptions d21c49b: java-xdebugger: avoid asserts 4f439fe: java-xdebugger: static group and this variable cf699a8: java-xdebugger: variables icons 26a0ffb: java-xdebugger: get nashorn frames this way until we integrate fully 3bf4519: java-xdebugger: correctly handle frame change f0b82ee: java-xdebugger: correctly handle session change feb4620: java-xdebugger: lazy value label calculation 0f99ccd: java-xdebugger: avoid gathering variables with resumed context 6073323: java-xdebugger: do not calculate top stack frames for all threads 4b2ff87: java-xdebugger: avoid NPE 0ac53b8: java-xdebugger: fixed dump threads action d9d1c74: java-xdebugger: fixed memory leaks c83bb60: java-xdebugger: tooltip evaluation support 3b0b8f9: java-xdebugger: expressions language selection UI b025aaa: java-xdebugger: removed duplicated debugger editors provider d6299a6: java-xdebugger: correct context for expression 2293837: java-xdebugger: do not deprecate old setters b0f9849: java-xdebugger: fixes after review af29d44: java-xdebugger: store condition with language and custom info 071b912: java-xdebugger: custom java breakpoint handlers 2635efb: java-xdebugger: add to watch support a3b7433: java-xdebugger: View text action support 570305e: java-xdebugger: filter library frames support dbe29fe: java-xdebugger: jump to object source support aef95ac: java-xdebugger: use debugger thread to store descriptors tree 04571c0: java-xdebugger: mark object 439666c: java-xdebugger: set value prototype - minor extra fixes 3c7f48c: java-xdebugger: set value prototype 9265407: java-xdebugger: support of "view as" action 74a63863: java-xdebugger: drop frame action on the debugger toolbar b09633c: java-xdebugger: restore variables tree state when stepping bf02fe4: java-xdebugger: fixed actions order 1c7a3d4: java-xdebugger: fixed thread name presentation 24fb430: java-xdebugger: correctly calculate frames d5d617a: java-xdebugger: avoid ArrayIndexOutOfBoundsException c160771: java-xdebugger: special icon for current thread 61d146a: java-xdebugger: drop frame action f631088: java-xdebugger: do not show empty type dc9789f: java-xdebugger: rebuild on auto variables setting change 223d0ae: java-xdebugger: return correct active execution stack d225fdb: java-xdebugger: jump to source 59a75a5: java-xdebugger: do not create old DebugSessionTab af21fe9: java-xdebugger: pause support 3aade1c: java-xdebugger: "view as" action prototype ad3f1fc: java-xdebugger: init breakpoints on process attach 8835958: java-xdebugger: dump/export threads actions on the toolbar 8ce7361: java-xdebugger: customize data views action in watches context menu 7252d5d: java-xdebugger: customize thread views action in frames context menu 00ab63e: java-xdebugger: customize data views action in variables context menu f2e28dd: java-xdebugger: use xdebugger's mute breakpoints state 1cdd4f7: java-xdebugger: settings popup support ca891ba: java-xdebugger: imitate old frames renderer ef0745a: java-xdebugger: threads tab support - update on select b857507: java-xdebugger: assert not needed 27d67ad: java-xdebugger: threads tab support 60986c7: toString for line breakpoint 2479d8f: java-xdebugger: threads combo support prototype d66fc12: java-xdebugger: watches support prototype d2fe211: java-xdebugger: variables support prototype ef6369f: java-xdebugger: initial commit: - debugger start - java breakpoints handlers - set/unset breakpoints - simple frames view support f4fb687: EA-56555 (diagnostic) 8b27b16: Cleanup (weird exception constructor) 75f96f6: better corners for Darcula a0fae704: Merge remote-tracking branch 'origin/master' 665e0e1: hang on start up 66df65d: rename test methods to run on java 8 (ClassFormatError fixed) 5898e80: Filter out remote sources dir from extra sys path (PY-12958). 0a0b678: hide service information 2b8c333: fixed type annotations restoring (IDEA-124889) ef7c8b9: new inference: inference in terms of inference variable as type params (I) 0bea7ea: new inference: encapsulation 922715c: Fixed buggy calculateExtraSysPath 6133865: CR-IC-5378 add comment on java.io.File.exists usage instead of vfs refresh b2d382e: IDEA-99541 New run configuration type to run Ant 14a4668: EA-56795 (diagnostic) ee0b565: Cleanup (nullability; parameter type) a95b6d6: Slim. Template languages must be over HTML_DOCUMENT element 3c41d20: Embedding Ruby code into Slim. ba802ea: Merge branch 'master' of git.labs.intellij.net:idea/community 3a51776: Merge remote-tracking branch 'origin/master' 37c2e28: Gradle: extra tooling model build error builder added 4874a78: switch off couple inspection 9ad3184: EA-55850 (a constant used is only available since Win7) 56cea62: resources -> src 78e49f7: Cleanup (typo) 7a4ac7b: EA-56033 (early diagnostic) e52b674: cleanup b55f2ac: WEB-6779 JS Debugger / Variables: Automatically show used variables: mutability 4077052: Merge remote-tracking branch 'origin/master' 8b18eb8: IDEA-123484: independent GroovyLineMarkerProvider. Don't suggest implicit trait methods in implementation list 2f60fb3: IDEA-123484: concrete trait methods are implicitly generated in inheritors a7eb2a0: IDEA-123484: abstract trait methods should have explicit 'abstract' keyword 2fbab8a: lazy Object type in GrLightParameter 44eaa05: remove dependency from Groovy PSI to Groovy completion 18fa4ff: split groovy completion contributor into separate completion providers ce1beaf: IDEA-124731 semicolon or curly brace after constants 3a2dfbd: IDEA-124731 enum constants can be placed on several lines with comma placed on the next line 4bdc91c: lazy light PsiType for fast creation from string. Use it where possible in groovy psi 8c44253: cleanup stub generator 46a6910: IDEA-125082 (Weaken intention for LinkedHashSet suggests AbstractCollection) 38ba59f: fixed PY-12964 add path to the interpreter doesn't work f07444f: uniformly handling class loading from paths containing special symbols like spaces 88eb679: Arrangement: store opened section rules instead of start comments a4e42e3: WI-23285 Arranger: sections is keep added (already existed section is not found) 224ff5c: save some memory by not caching constructors in picocontainer; they're not reused anyway 3a25aee: DevKit: add InspectionDescriptionNotFoundInspectionTest.testHighlightingForDescriptionCustomShortName ed33e55: revert changes that made tests hang fedbb1d9: IDEA-124403, EA-55541, EA-55517, EA-49088, EA-49127 soft wraps recalculation issues 6112926: EA-55847 - AIOOBE: ImmutableText.charAt d2d6f45: cleanup (following review #212) e4f6aa4: EA-56779 - IVFAE: PersistentFSImpl.getFileId 2004f6a: improve description 16bd2ee: add "Suppress for 'Tests' scope" quickfix to "Prohibited exception caught" inspection f96b846: new "'BigDecimal' legacy method called" inspection 2be4b97: better layout for combobox eb6acaf: svn: Refactored RepositoryBrowserDialog.doGraphicalDiff - moved diff logic for "url + url" to SvnKitDiffClient ed5d225: svn: Refactored RepositoryBrowserDialog.doGraphicalDiff - do not wrap obtained changes in custom UrlContentRevision (see c38efc0eaffe39c4ac4250cdd4c2615a321db906) - changes collected by SvnDiffEditor correctly work with "Show Diff" action fb0c65a: InternetAttachSourceProvider: don't sync refresh from outside edt (EA-56768) 9770742: EA-56761 - PIEAE: ClsRepositoryPsiElement.getManager 8317a56: EA-56519 - CCE: PsiDocumentManagerBase.handleCommitWithoutPsi 2ecda67: vfs: create handler as soon as archive root is loaded b9b3a28: Cleanup (unneeded second refresh dropped) 00140af: IDEA-124361 Suggested variable names for Optional variable needs improving b92c65c: svn: Show "changes viewer" dialog even if changes collection is empty (dialog will display necessary information message by itself) 90a5b72: Merge remote-tracking branch 'origin/master' 6eb4127: fixed PY-11909 problem with extract variable a9d6cb1: svn: Moved several utility methods to SvnUtil class 71177eb: fixed PY-11922 pytest problem with marker expression containing spaces f895885: [log] IDEA-124546 enable "Edit Source" from commit list 3a483ab: [vcs] Delegate to the fuller constructor 8bc8177: fixed PY-11929 Insert type assertion should be disabled for references introduced in dict comprehensions de5a5e6: Add new icons for new arrangement section rule 19d7bf9: Merge remote-tracking branch 'origin/master' b61e49e: [log] Trim the hash in go-to-hash action a351cff: fixed PY-12037 long path cause wide menu 5972053: touch file to recompile 3e8ef45: continue WEB-6779 JS Debugger / Variables: Automatically show used variables 0c8bcaa: init WEB-6779 JS Debugger / Variables: Automatically show used variables ce66c08: compute memberFilter only once 1701927: IDEA-124688 Console scroll to the end - jumps on the end of the line sometimes 287390b: be prepared to event log changes when expiring notifications (EA-53620 - IOOBE: MarkupModelImpl.addLineHighlighter) 296a5dc: Platform: deleting shortcut from bound and inherited action fixed d0e540a: IDEA-106517 Exception on welcome screen when using speedsearch 5978682: svn: Refactored DirectoryWithBranchComparer - SVNKit diff logic moved to SvnKitDiffClient fc13a83: IDEA-116057 second-keystroke popup 1fe493a: fixed PY-12120 Invalid caret position after Enter press in unicode strings 69b6e2e: check for UserDataHolder directly 5cd9a8f: svn: Refactored SvnDiffEditor - use File instead of VirtualFile 8511042: diff: add icon for synchronized scrolling 8e9af01: js postfix templates: if, else, return, throw a309ba7: Remove Open Directory action. 23db467: use Couple fc77edb: fixed PY-12195 Changing signature of decorator removes '@' 6a1b621: cleanup 5653e4a: IDEA-124974 NPE from Switcher if 2 tool windows have the same first-strike char f74c773: do not log refresh stacktrace 6da5c0c: OC-9871 fd6d2fa: Gradle: tooling version updated in libLicenses.gant 0290479: use Couple e44b143: use Couple baecc09: use Couple 3a60ce3: use Couple 47f6b1b: IDEA-125121 MacMessages: NPE when parent is null 637a597: do not expand stubs when evaluating getContextName c39f3b1: Gradle: update Tooling API version: 1.12-rc-1 => 1.12 bbfc26b: IDEA-125119 NPE if message for MacMessage is null 5991df3: IDEA-124839 Gradle sync reports "Error:You can't change a configuration which is not in unresolved state!" and "Could not resolve all dependencies" 19c251b: fixed PY-12313 Incorrect __file__ value when running tests in a folder on Windows f9d754d: IDEA-124839 Gradle sync reports "Error:You can't change a configuration which is not in unresolved state!" b186522: @NotNull 4e90ea9: dependency fixed 3e98719: removed lang-api dependencies e5ba40d: removed dependency on platform-api 19444a1: notnull 4a8f5f8: @NotNull 9accb24: moved to core 38f3c11: moved out of psi c4390c4: Fixed IDEA-122488 IDEA 13 1 not using default font [CR-IC-5349] 8667c40: do not update when root name not changed 4569c83: fixed PY-12369 Code Inspection fails for negative default parameter 20c2b28: update plugins: check plugins according to the new version to be patched (IDEA-78385;IDEA-124308) 5f74804: IDEA-124543 sout template formatting f0918e0: fixed PY-12401 inline refactoring looses comments 851fd3b: IDEA-124305 JSP: Import statements suddenly disappearing every now and then 850ea16: typo acac62d: Cleanup (locale conversion; properties grouped) 21152ea: Cleanup (test simplified) a979900: vfs: core JAR FS migrated 4bf38d4: vfs: archive file system 96aad22: IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates; project leak fix 607ba58: Platform: keymap tests cosmetics c6354dd: accept as cleanup tool 85f72e1: IDEA-123379 (Unable to generate toString() with template "+ super.toString()" if sub class doesn't have any variables) 2e1a1ab: fold some IJ boilerplate in console fd7f7a6: remove PSI event nesting because of eager PushedFilePropertiesUpdater (EA-56525) aafb2dc: use ensureValid (EA-56712) 5494673: TodoIndex supports snapshot mapping e676714: myContents shared snapshot index can be reset via clear (due to todoindex dependency on settings) 55f9327: use TW stripeTitle if needed. skip extra popup-step in case of one item. 8b36033: separate NavBar action place into popup and NavBarToolbar places (IDEA-124199) 3e3b44b: fixes for review comments 136d116: move normalizeMemberName to debugger view support b3675f7: IDEA-56033 Mercurial: add support for reverting an uncommitted merge 2b804da: IDEA-124393 Mercurial: Log: user filter applying causes empty log 27272f3: EA-55721 - assert: DbElementImpl.getDataSource 8c49254: EA-56008 - assert: DatabaseVirtualFileSystem.getProjectSafe 42cd37cc: related to EA-56292 - NPE: ComboBoxFieldPanel.createComponent c4a273f: EA-56671 - E: Runtime.syscall bffc362: adjust offset while looking for selector 6ef97d6: EA-56674 - IAE: DbFindUsagesHandlerFactory.canFindUsages c96459f: postfix templates convert configurable postfix list to tree & change store strategy 8481ffc: IDEA-118554 (Inspection suggestion: BigDecimal divide() without specifying a scale and/or RoundingMode) 69d1364: batching tasks to reduce the number of events posted to EDT c4e2bbe: remove useless HideFunctionValuesAction (now we correctly grouping functions) a862f08: Merge remote-tracking branch 'origin/master' 2386bed: testdata for IDEA-24479 760d73e: use manager.getProject (CR-IC-5302) 5c11efb: Merge branch 'master' of git.labs.intellij.net:idea/community 5ab59ac: EA-55808 - ISE: ComponentManagerImpl.getPicoContainer - a more robust fix 543d9f6: Merge remote-tracking branch 'origin/master' 5b53af1: Merge remote-tracking branch 'origin/master' 8de4646: IDEA-123896 Navigate -> symbol action doesn't find overloaded methods 7dc78a8: IDEA-124772 Code completion in import statement: suggestion shows package from "java.lang", but when it's selected "java.lang" prefix isn't 7e77d3d: Merge remote-tracking branch 'origin/master' 4b6debd: Merge remote-tracking branch 'origin/master' ad58ba7: results of code cleanup 1c55611: do not inspect binary files 0feba83: warn about raw arrays passed to varargs method (IDEA-16977) b32b333: assignment fix for super wildcards (IDEA-125031) 6e2f355: EA-56686 - NPE: UnusedDeclarationInspection$$.runInspection afe28ba: provide editor with project - no harm (IDEA-124656) a02113f: Remove class. 304f5dd: IDEA-124097 Structure tool window steals a focus 174a488: Merge branch 'master' of git.labs.intellij.net:idea/community 6a0d559: Remote libraries stored in a directory separated from skeletons 0f964da: aware of not sourcemap file adfec67: fix NPE Field is not nullable: className a0a681e: IDEA-124956 PsiShortNameCacheImpl.getClassesByName() is O(N^2) 5b4eafc: Rearranger: allow nested sections processing b638b32: Merge remote-tracking branch 'origin/master' c7bcc11: make "Unpredictable BigDecimal constructor call" inspection and quickfix more accurate 6ee9d29a: read saved index data by default + save empty indexed results ebece42: WEB-11680 chrome debugger doesn't start due to internal exceptions e2ceeec: WI-4722 Debugger: Ability to skip certain functions with step into. b63b703: continue WEB-11775 'Do Not Step Into' groupings ec71671: cleanup c309c6a: cleanup 0abe2e1: fix tests 51e2856: Merge remote-tracking branch 'origin/master' 1edc667: invalid psi range diagnostics (EA-49842 - assert: ExtendWordSelectionHandlerBase.select) dd4697d: IDEA-124379 Avoid completion lookup glitching 7732843: IDEA-85517 Option to collapse by-default manual defined (editor-fold) regions [CR-IC-5228] 095153a: set explicit locale environment: GeneralCommandLine.getCharset() and LC_CTYPE should be the same, remove dependency on project and application default encodings f4cd58b: DevKit: add InspectionDescriptionNotFoundInspectionTest 75ef7eb: fixed EA-53387 - CCE: PyElementGeneratorImpl.createParameter 440a2e5: Merge remote-tracking branch 'origin/master' f1842c2: fixed EA-56204 - IOOBE: SegmentArray.findSegmentIndex d5747a8: fixed EA-56667 - CCE: ReplaceListComprehensionWithForIntention.createForLoop f72f65c: DevKit: simplify/remove dups in DescriptionNotFoundInspectionBase, add tests 520268f: fixed EA-56673 - IAE: ChangeUtil.copyElement 6edaf52: fixed EA-56683 - NPE: PyStatementMover.moveTheSameLevel e78a1f8: Postfix cleanup af4c18c: fixed EA-56684 - NPE: PyStructuredDocstringFormatter.formatDocstring 51255dd: Merge remote-tracking branch 'origin/master' a6f328b: code cleanup available as intentions (IDEA-38653) 0e05ee3: Fixed a typo. d350749: IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates a34f27b: Fix output handling. 6034330: DB: improve find usages grouping 0756490: scopes combo: filter duplicates, suppress internal-modules 2a680d2: DevKit: extract PluginDescriptorChooser, improve plugin.xml candidates list presentation, fix dumb mode error 598528c: Merge remote-tracking branch 'origin/master' c64f813: hide empty vcs scope when vcs is not configured 2e0f935: update "Select word at caret" to "Extend Selection" in tips (IDEA-124727) cc92f9a: use StringUtil.trimStart() CR-IC-5322#c26136 dfe9c11: DevKit: do not search in non-XML files for ExtensionPoint DOM usages CR-IC-5321 2fa4de5: ActionTestCase kicked 94c3177: fix puppet tests: clear extension cache on point registration 1d3458a: copy reference for directory: copy the relative path from some root (IDEA-92885) 3f1567e: enable CopyReferenceTest.testMethodOverloadCopy dffcdb3: rename "Select word at caret" to "Extend Selection" (IDEA-124727) 2dc0e67: IDEA-124935 Completion font issue on Spring b210fef: private EditorHyperlinkSupport.HyperlinkInfoTextAttributes c394f80: cleanup b3840bc: Cosmetics b05ddda: DevKitBundle: use AbstractBundle 847d67f: continue JS Debugger test framework — stepping spec 578a54b: cleanup cad6541: IDEA-125004 DevKit: support plugin.xml <depends> "config-file" 873fa26: Github: remove test a7ae56f: Github: do not catch OperationCanceledException explicitly 63ef800: EA-52410 Github: do not throw runtime exception on parse error fad9ec0: Github: fix dialog type 3c53f98: Github: remove final 0c7b058: Github: catch runtime exceptions in modal progress f08ff4c: Github: GithubFullPath case-insensitive 0204ba2: access to super members fixed (IDEA-124985) 7ab104a: IDEA-124985 74f3980: IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates 11d2cc4: restore EditorHyperlinkSupport.getHyperlinks for EA 5f8a926: let EditorHyperlinkSupport.clearHyperlinks clear the hyperlinks 9219a05: Attach Debugger in Python console. e85f16d: IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates c5c6471: EA-45164 - more TypeConversionUtil.getSuperClassSubstitutor diagnostics 28d0e2e: javadoc for clearHyperlinks deprecation 1fe25c5: EA-54479 - CCE: CustomFileTypeCompletionContributor$.addCompletions afba911: Emmet: use couple instead pair 3d63853: Custom templates: unify retrieving offset approach 0badce5: png optimization df16471: move generated icon classes to new generated roots 420255e: patched AbstractClassGenerator from CGLIB moved to util module because it's used from InstanceofCheckerGenerator class 92d4c4c: "Node.js Express App" doesn't relate to "Static Web" group f78f659: IDEA-124877 Run Configurations: Allow sort configurations under type or folder node (Exception fix) 7272ef6: remove copyright from intellij splash and about dialogs be38201: manually render copyright 9c0ccb4: +copyrightForeground f4cb6a8: Merge remote-tracking branch 'origin/master' 35f0811: fixed PY-12915 No project interpreter found after project creation aeb677d: Start plugins wizard #28 (be Ubuntu-friendly) ad086fe: Merge remote-tracking branch 'origin/master' c78ae5f: cleanup tool -> inspectionEP b52cf11: Fixed wrong usage. 421efd0: we must avoid use UUID.randomUUID — can cause long network calls 0ea9f4b: https://groups.google.com/forum/#!searchin/netty/netty$204.1/netty/8jf6SPFiN6g/nLg7opwUsxwJ 503f8cd: IDEA-124871 Can't build project if its name contains colon: convert project only when it is used as directory name 5bf5dd0: static methods in interfaces can't be hidden in subclasses (IDEA-124921) ec8f194: Extract execution timeout registry key f599645: fixed PY-12920 **kwargs in constructor parameters disappear after "Add super class call" quick fix 6a9db3b: Extract execution timeout registry key 26baf8f: extract superclass: pass target class in after data 838771a: code cleanup: allow to choose another profile; filter view to show cleanup tools only 2a25c8c: code cleanup (initial) 246bf70: Merge remote-tracking branch 'origin/master' 6e62c61: reverted back dc0ad20 due to PY-12904 IAE: Equal objects must have equal hashcodes 1eb6f78: - do not set databuffering if it was already set - make notifyAll in leave of StorageGuard if somebody is waiting 25ccd86: less lockStorage for put / get operations + store value file offsets in btree enumerator directly 1c8aaa4: lazier reparse range calculation b488d43: incremental reparse should happen only on nodes fully covering the changed fragment (EA-54262) 66da2af: more diagnostics and possible fixes for EA-46770: don't let code fragment documents be gc'ed 79ff607: EA-51141 - IAE: CreateFromTemplateAction$.getActionName 277ffe0: EA-54226 - simplify JavaFileManager, remove "access only after startup activity" assertion 4b22fa6: EA-54691 insert completion char in write action f4f67d2: EA-56504 - read action b515187: less lockStorage for put / get operations + store value file offsets in btree enumerator directly f0bdde8: move serialization of value container inside valuecontainer + added code for saving to use existing bitset used for large index values f0dcc74: magic number moved to registry e211432: check validity of RangeHighlighter 21afe13: [vcs] IDEA-120737 Change Merge button caption to Merge... c5bcb11: [git] IDEA-118125 change url for Detached Head information 60036d0: PY-10016 Namespace support in PyCharm 2.7.3 c02eade: DevKit: highlight <extensions> "xmlns" as deprecated 2b0d162: Devkit: remove non-stub test data 34d6a8e: include PIEAE invalidation trace as an attachment 571bdea: EA-56524 - check for virtual file validity when searching in its document d0a9cac: EA-56551 - don't expand structure view for invalid dom elements 7a6616d: EA-56593 - FindInProjectTask read action 73d32e6: move TraceableDisposable's own trace to the bottom as the least important 3fb8ff0: continue JS Debugger test framework e426c3e: Platform: redefined shortcuts for bound actions work in inherited keymaps + such shortcuts is shown in the UI tree, in spite of being 'bound' (OC-9826) 7859a0d: IDEA-124960 DevKit: "register extension" fix for EP defined in custom plugin bce419f: Devkit: rename/move RegisterExtensionFixProviderTest missed file 9359908: relaxed diagnostics 37894fc: Devkit: rename/move RegisterExtensionFixProviderTest 544ab30: CR-IU-696 - use activationComponent 0194c34: Devkit: add RegistrationProblemsInspectionCodeTest 92e0c60: extract PluginModuleTestCase d5a13c3: rename 28ea4b5: Don't evaluate debugger vars in EDT. 5529340: Fixed args. 5d4bea7: Merge remote-tracking branch 'origin/master' 7846df8: Backported more Pydev stuff including Stackless debugging support and AppEngine debugging fix. 5214a06: DevKit: add XmlRegistrationProblemsInspectionTest 3aa92a1: Merge remote-tracking branch 'origin/master' 3ea1686: Backport some minor Pydev fixes. f80095e: Rename modules. 8e6e512: [log] Don't send performAction request to the graph if below the log fad27ec: Commit document before creating callback fd61469: Allow emmet preview for xmlGenerator only abe4c7e: Fix Emmet preview for big abbreviations c8bb209: Fix emmet preview in injected fragments ddcf07c: Live templates: add diagnostic f5da90c: fix tests on linux (filename case) 5743b43: Merge remote-tracking branch 'origin/master' 48d9080e: Ability to perform force update when there are uncommitted merge added 001903a: clearer test data file name 11fdf63: Merge remote-tracking branch 'origin/master' e72fd1a: Fixed conversion. af0ae88: for CR-IC-5142 bff450e: make test light e3d5657: IDEA-124876 ("Mismatched query and update of StringBuilder" false positive with lambda method reference.) 3f9ce9c: IDEA-106749 DevKit/ComponentNotRegisteredInspection inspection does not handle optional dependencies properly 39f062f: store complete map results for snapshot supporting indices 743ae27: Remove 'Support' from settings name. d6c5e1f: Create thread on attempt to suspend on non existent thread. ad86a82: Merge remote-tracking branch 'origin/master' d42e997: We treat not started threads as alive, to support debugging of Python 3.4 threads created by start_new_thread. cfd0595: IDEA-122909 Mercurial update: clean option 6aae6da: Save all documents added before update and merge actions from branchPopUp 206d45f: SOE 51aa5b4: NPE fix bee86ca: new Pair<TypeA, TypeB>(a, b) -> Pair.create(a, b) d659703: DevKit: add ComponentNotRegisteredInspectionTest 28dce08: IDEA-124032 IDEA plugin: Can't find com.sun.xml.internal.messaging.saaj.soap.LocalStrings bundle command line property set to true by default 262d5a9: IDEA-124871 Can't build project if its name contains colon b3557e9: refactoring postfix templates 20fbada: IDEA-124032 IDEA plugin: Can't find com.sun.xml.internal.messaging.saaj.soap.LocalStrings bundle added command line property (false by default) 2d0c2f9: don't count 'runtime' dependencies when showing a warning about circular dependencies e5e5915: IDEA-124859 Runtime module dependencies are not compiled when run configuration with dependent module is launched c1980f4: check Pair types with actual parameters types 16906b2: IDEA-118714 Problem in automatically changing branch on tasks switching c177312: IDEA-123898 IntelliJ Configuration server : create/manage JetBrains account error 7370dd9: new Pair<TypeA, TypeB>(a, b) -> Pair.create(a, b) inspection for lang level < 1.7 136ade1: fixed PY-4479 Add field to class: select created field for editing, not passed to constructor parameter e7f0c33: add both add field and remove param QuickFixes for the param in __init__ method 00b00b6: Merge remote-tracking branch 'origin/master' 2d20acb: Merge remote-tracking branch 'origin/master' 3b0a609: track PsiFile invalidation trace 68ffeb6: use ensureValid (EA-55092) a51e36f: add PsiSubstitutor.ensureValid (EA-55730, EA-55738) 9f4593b: use Couple in util a249d4e: fixed PY-12825 Remove unused parameter: do not allow to remove last argument after star when refactoring function with keyword-only arguments 4ffed7a: IDEA-121171: fix failed tests c053844: convert testng -> junit e5b9d92: use Couple 5543b2f: use Couple d156a40: convert testng -> junit 43ba882: inspection and quick fix for Couple class 7411352: testdata fixed 4d5b798: restore test 74ff7fd: testAssistance -> DevKit 03640d1: EA-56450 - CCE: JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation 5455834: IPython should be enabled by default. 25a4149: Fix option label text and size. 514ddf8: Merge remote-tracking branch 'origin/master' b69e716: Return None in case of unknown source. 328fb7d: don't report ignored ioexception f0a2a53: No need to inform about failure. 541a3d3: fixed literal conversion. 11e19f2: IDEA-124877 Run Configurations: Allow sort configurations under type or folder node 6e84490: Do not delete inserted semicolon for statement-based postfix templates 7b768e0: Simplify return postfix template 9e18381: Reformat postfix templates tests f7abe52: Delete dummy semicolon after postfix template expansion 75264a6: Cleanup postfix templates 337ddff: TemplateManager -> service f6cc0f9: use ensureValid (EA-56464, EA-56467) 2b3b0f3: EA-55808 - ISE: ComponentManagerImpl.getPicoContainer c685b88: fix "already disposed" from EditorNotifications de62ac0: Devkit tests: add @TestDataPath ed97d68: PluginXmlDomStubsTest: move test data 7f98202: PostfixTemplateDescriptionNotFoundInspectionTest: rename/move test data 6d49cc4: extract ExtensionPointDocumentationProviderTest aebd2ef: PluginXmlFunctionalTest: cleanup inline test data 2bdefc7: No sets language without project (fix for ui-designer creating over default constructor) 4d0fde11: svn: Refactored SvnVcs - moved ourBusyExceptionProcessor to RepeatSvnActionThroughBusy 81f13d8: PluginXmlFunctionalTest: fix enabled inspections 8656e4d: rename/cleanup InspectionMappingConsistencyInspectionTest 2e6a042: extract DevKitImplicitUsageProviderTest 29ac0ab: PostfixTemplateInspectionTest -> LightCodeInsightFixtureTestCase 494bc38: OS X: fixed NSString and NSOpenPanelDelegate_ leaking add7462: Fix indentation to conform PEP8. 382ab4b: DOM stubs: exclude some dom extenders from stub building 72d5787: EA-56189 - ISE: LocalCanBeFinal.checkCodeBlock 788f777: EA-56308 - NPE: UnusedParametersInspection.checkElement 6dfed9d: EA-56333 - assert: PsiMethodReferenceCompatibilityConstraint.specialCase 606d8ea: EA-56286 - AIOOBE: BringVariableIntoScopeFix.invoke 659e657: svn: Refactored SvnVcs - removed old code that deletes previously used notification groups fec2014: svn: Refactored SvnVcs - removed unnecessary logging 33da31b: make dumb aware 2c7c9e1: IDEA-124663 (Refused Bequest inspection should honor @OverridingMethodsMustInvokeSuper annotation) c37b1a4: Merge remote-tracking branch 'origin/master' 08cf27c: select exact match in install package dialog 64f7299: read access d83af54: accept raw substitutors during diamonds inference (IDEA-124836) 16b6498: [git] fix some editable comboboxes 27a2e0f: [log] Fix transitivity in compareTo 7e86caa: DOM stubs: exclude some dom extenders from stub building bf339b6: Repository refresh added after pull action 8e41d7d: use Couple a285781: +getEmpty b4b6cc6: fixed PY-12660 PyCharm adds quotes in runconfiguration and fails 5f75f69: svn: Refactored SvnVcs, SvnUtil - removed unused code, warnings fixed, code simplified 85c621d: svn: Refactored SvnVcs - updated deprecated VcsListener registration 94af0a5: Merge remote-tracking branch 'origin/master' a26b016: easier logic for indentation in console and fix PY-12542 209eb14: fix for PY-12542 and improve indentation in console logic 9b97079: fill PyConsoleIndentTest with new tests and improve old 2aa7076: fix console crashing on IPython completion (PY-11645) 0dbd022: editor now save file on transition to Python Console (PY-12487) 265a763: move console startup commands to Starting script field in Python Console settings (PY-11728) 74aa6cc: add checkbox for disable IPython in Console settings (PY-7425) 5f5a2bb: restore EditorHyperlinkSupper.addHyperlink for EA binary compatibility af43068: OC-9742 e685f38: less disk operations on integrate 9db3107: fix expected wildcard types f29a167: fixed PY-12679 Remove redundant parenthesis: false negative for duplicated parenthesis in complicated and or statements cc743c3: testdata for JDK-8042508 1ab69ce: stream migration: missed qualifiers restored (IDEA-124820) 8862613: variable type by expression type suggestion (IDEA-124816) 909915f: Merge remote-tracking branch 'origin/master' dc0ad20: fixed PY-12698 Noticeable hang when selecting not yet added virtualenv as project interpreter f91fcdb: svn: Refactored SvnVcs - SVNKit related initialization logic moved to SvnKitManager b67eac0: svn: Refactored SvnVcs - encapsulate access to configured ssl protocols fa6941f: svn: Refactored SvnVcs - inner classes moved to separate files (and renamed) 0da2c6c: svn: Refactored logging logic in SvnVcs - code simplified, duplication removed 250b00c: IDEA-124250 Mercurial branches sorted in push dialog 17bf1db: ignore @org.mockito.Captor (IDEA-124802) 17e28ba: cleanup invalid fold regions (fix console leaks, IDEA-124626) d2ead52: move postfix templates to lang-impl d13a4e1: Emmet: add tests + fix existing ones f9e13cb: Emmet: fix preview for abbreviations with 's' filter 6799aa2: Emmet: move calculating template text into hint alarm b6f41b4: Emmet: parse incomplete more/climb abbreviations 3bc5114: Dispose hint on inner editor released d28aae1: Emmet: performance improvement 0ef5647: Cleanup emmet generator 88dcca7: Emmet: fix logging message 83deceb: Emmet: add new action for preview 14b4449: Fix typo b333197: Emmet: performance improvements, add segments limit. 3d5fcbc: Emmet: show new preview only if it's enabled in settings b53ff16: HTML: enable autopopup after < and & only be5c39d: Brand new emmet preview c8ec330: Extract logger 6ca1101: fixed PY-12786 Python Interpreters: extra space in configuration popup from project creation dialog 1a15783: fixed PY-12824 Remove unused parameter: usages in function calls are not updated 03a2ae2: IDEA-116630 Run/Debug button disabled sometimes after breaking make process (and hanging thread) 07613ed: svn: Refactored SvnKitManager - @NotNull, removed duplication 2c91e9a: restore deprecated EditorHyperlinkSupport.clearHyperlinks for broken plugins 7c1c4b1: fixed PY-12825 Remove unused parameter: do not allow to remove last argument after star when refactoring function with keyword-only arguments 520b4be: fixed PY-12826 Remove unused parameter: remove references in the docstrings 2311a48: some additional checks for consistency b79e433: svn: Refactored SvnVcs - methods related to SVNKit clients/repositories creation moved to separate SvnKitManager class 73c5925: better "cannot create branch from repository with no commits" problem handling it was unclear why "Create branch" option is not available for just created repo. b28779b: IDEA-124570 (diagnostic) 65e5214: merge EditorNotifications requests, update automatically on dumb mode changes 4a210b0: IdeaPluginConverter#getAllPlugins: get rid of isIdeaProject() call (DOM stubs interfering) 87b041d: move postfix templates descr to resource-en 7ef1c6d: svn: Removed unnecessary SvnUtil.formatRepresentation 4c7c29f: Run/Debug buttons stay disabled, thread hanging if external tool configured as 'before launch task' fails to start. 8b762a5: Merge branch 'svn_18_3' 7ee2226: Merge remote-tracking branch 'origin/master' b44a1bc: Removed unnecessary EP, introduced Rename Handler for Python Magic Literals: fixing some tests 6c5b423: revert IDEA-123956 Anonymous class formatting moves all args to the next line (32ae79905cb025f6bc213a925f1f4e58e9d6b8f7) 404cf1a: Merge remote-tracking branch 'origin/master' f0ac2bd: unnecessarily qualified statically imported elements: do not ignore chained calls (IDEA-124806) 6f548f2: skip tests under resources roots 51e7e1c: compiler configuration: distinguish compilable resources (IDEA-124599) 6a76a7e: ignore deleted custom repositories (IDEA-124796) a32723b: postfix template description inspection + tests 85f2823: remove alarm. Make SE faster 32ae799: IDEA-123956 Anonymous class formatting moves all args to the next line [CR-IC-5212] 6094264: Cleanup (unneeded interface) 899e7e3: [git] IDEA-124052 Support remote refs w/o a correspondent remote + test 172a3f9: [git] Don't log error in case of empty config file - it is allowed 95468ea: [log] Don't report the error too often 09f5029: [log] Fail safer if no refs were found at some head commit ea5506c: WEB-10560 Debugger: second Mute Breakpoints invocation doesn't work b967e4a: removed extra unneeded delegate 815a632: for given fragment: calc hash code once and do not use wrapper CharSequenceSubSequence for interning store CharSequence into Map of int -> CharSequence+ 06778a8: cleanup e01a5af3: initial d197ca8: reformat only changed text checkboxes are enabled (IDEA-121171) 1c6ba24: Start plugins wizard #27 cleanup 78e7840: WEB-12106 node-webkit crashes when opening developer tools 61b298f: ^461 don't create invalid range marker 5790679: getter invocation in case of object-backed scope 2a38f58: IDEA-115737 Mercurial problem on Windows when repository replaced right inside disk directory. 7d53080: Merge remote-tracking branch 'origin/master' a7bb442: Merge remote-tracking branch 'origin/master' 459d870: ignore @org.mockito.Spy (IDEA-124802) efa4d64: junit 4 library setup (IDEA-124780) 85f6ea1: IDEA-121171 Reformat only VCS changed text - does not work when editor is not opened 765dacb: cosmetics 753dd85: do not remove contents added by other subsystems, which were run independently from any compile session (e.g. ant build) 6e20824: capitalization f09a084: ensure cancel definitions search on popup closing 95e2ed2: Merge remote-tracking branch 'origin/master' 420f392: WinPty libs for Win XP. 161dd99: Removed unnecessary EP, introduced Rename Handler for Python Magic Literals: fixing some tests e593086: remove unnecessary file f585fcd: make test light 0e4f67f: IDEA-95363 ("for loop replaceable" inspection error) 1e1bb69: fix compilation 3078cb5: restore com.intellij.openapi.roots.LanguageLevelProjectExtension.reloadProjectOnLanguageLevelChange as deprecated ae82d08: IDEA-124688 Console scroll to the end - jumps on the end of the line sometimes 5348fc6: IDEA-124644 Comparison of negative zero with positive zero incorrectly marked as always false 0897305: AIOOBE (IDEA-120790) 86141d8: assertion e461a9bc: IDEA-124755 "Unnecessary {@inheritDoc} Javadoc Comment": do not warn when additional tags are present 4e13faa: Fixed IDEA-118781 Eclipse code style import: White Space: some categories are not applied b306260: Fixed IDEA-124647 Quick switch scheme > switch code style scheme does not work db2e799: don't clear cache for disposed MessageBus, fix tests 4c5d8e6: a higher output threshold for "Too much output" in console to avoid this message on long command lines 5b27a1f: navigate to function source: respect our navigation policy 1a04727: Merge remote-tracking branch 'origin/master' 288ccfa: most specific check: accept lambdas when target type is type parameter (IDEA-124725) 78e9bb7: type parameters should not cause deprecated constructor warning to appear (IDEA-124689) 91f6308: redundant suppressions: take into account alternative ids (IDEA-124690) a2a076c0: lambda -> method ref: reject anonymous class replacement (IDEA-124748) dc73135: accept static methods with body in interfaces (IDEA-124745) e4a77b6: check suspicious ConcurrentHashMap.contains (IDEA-124698) 35206e4: uncomment testdata 2ae7053: check inferred type test 4cefdc5: testdata for IDEA-124547 51f1e0e: add option to ignore specified AutoCloseable subtypes f8d2553: find field in superclasses also 747928f: fix broken readSettings() logic 83f842a: make magic checkbox work on private fields dac9905: remove faulty annotation 24bdcbf: DOM: optimize JavaMethod annotation handling dcdbc00: move MessageBusTest to platform-tests to avoid cyclic dependencies involving util 1da0bf9: save a bit memory on non-root message buses, relax test expectations a bit 0b888e5: IDEA-122914 (unclosed zip files) cf649f8: [git tests] Dump to stdout if the test failed 9214eb2: [tests] Move enable debug logging for certain categories to a common place 32597b1: better java doc 2ec1705: fixed PY-12698 Noticeable hang when selecting not yet added virtualenv as project interpreter d87049a: Merge remote-tracking branch 'origin/master' bc78e99: RunConfigurationExtensionsManager API improved 8d20600: Cleanup (obsolete logging) 4a61e1a: Show debug command line action renamed (PY-12835). 4725ae6: Merge remote-tracking branch 'origin/master' 21de2af: fixed PY-12848 Adding local Python SDK does not work c1c98cb: Merge remote-tracking branch 'origin/master' 7bd7aae: don't show hoisted variables 6de7d54: move BasicDebuggerViewSupport up 11656b8: init: don't show hoisted variables f1b95b5: ColorChooserIntentionAction.isInsideDecodeOrGetColorMethod: use constants 00ee9ed: Merge remote-tracking branch 'origin/master' ce4bafa: Until build moved forward. 2806dd8: OC-9570 OC-9663 0f15b6d: restore the ability to clear console from any thread bb44094: IDEA-124646 Option to turn off "compilation successful" popup adac2da: style: optimize if-statement and assignment c32cafb: style fcc2f18: Remove code duplication. 58be81d: Removed unnecessary EP, introduced Rename Handler for Python Magic Literals. b2c7dea: fix console highlighting of lines added one by one, dispose range marker 56beb0e: take into account buffer overflows when calculating console fragment to highlight & fold 9065b24: be less public in new EditorHyperlinkSupport API 5f39988: clarify a bit when hyperlinks & foldings are disabled in console 18fdcfd: disabling of foldings removed 84162a7: continue processing when the output stops 97474ce: revert of condition 358ff50: continue processing when the output slowed down under the threshold b19c269: more eager disabling b788f32: removed todos, no issue here. 88ead50: removed manual action e26bb7f: continue processing from last location - commit fix 15d968a: continue processing from last location 03969ac: removed myHighlighterToMessageInfoMap f60543f: disable console when there is too much added text removed EditorHyperlinkSupport#myHighlighters list which seems redundant and would need some smart clearing. 9d3bfdf: little experiment c572e4a: ^461 revert: we must create lazy range marker delegate on document changed, otherwise invalid delegate will be created b828042: background notifications: cancel on file invalidation; don't leak e429328: cache editor char width a8e14ae: relax testStaticImportInTheSameClass expected timing 676f08a: IDEA-124317 super class method is not shown in basic and smart completion, while accessible a655925: ability to serialize internal classes 51fabf9: cleanup fe4a711: rename to BasicDebuggerViewSupport 0fa7a11: rename to RemoteVmConnection a82fe46: init WEB-11968 Support debugging with embedded Chromium using projects such as CEF3 d3d775b: update editor notifications in background 2a77c0f: maven tests: tearDown more f0a6a44: IDEA-124476 (slf4j parameterized logging inspection: add option to only apply to certain log levels.) 54ae382: we must create lazy range marker delegate on document changed, otherwise invalid delegate will be created 0c7dbd9: cleanup 991f719: we must check getLine() at first, because getOffset() can cause dramatic side effects 5cdeb11: ^192 fix selection d652d59: done WEB-9842 Node debugging: Hitting a breakpoint with a local variable in scope that is a large buffer will cause the debugger to hang for a _long_ time WEB-9834 Node.js debugging: variable value calculation takes a while WEB-1892 NodeJS, Debugger: deadlock after stack frames has emptied WEB-7945 clustered view of Buffer class 73a6343: init: move getIndexedProperties to ObjectValue 3b4ad30: IDEA-124593 (Inspection "AutoCloseable used without try-with-resources" flags System.out.printf) 4290300: IDEA-124654 (replace with chained append() calls gives wrong result when the object is unknown) 4b68768: drop unused property 28c75d2: remove check covered by "Variable is assigned to itself" inspection (IDEA-124559) 5201ba0: prevent maven test initialization failing to spoil the fixture for other tests 1b55349: faster invalid line number detection in console exception filter (IDEA-124626) db58c9b: IDEA-124556 MessageBus event processing should be faster with many child buses and (almost) no listeners 77c7af8: optimization for getChars handling 48a56e0: PY-12846 ("show hidden files" configurable through FileChooserDescriptor) b0679d6: Cleanup (builder-style API; arrangement; duplicate deprecation) 4f5db0a: [git tests] fix paths comparison fa24163: [git tests] simpler method names 6d469a1: [git tests] Fix testdata for cherry-pick 600259a: [git tests] Remove the test root directory after test execution, reorder teardowns e422a99: [vcs] Fix already disposed exception 7cb3043: [git tests] turn cuke tests back on. f9d83e6: [git tests] fix GitAddSteps 49fecac: [git tests] Make sure other tear downs finish even if one fails e0847db: [tests] extract dumping log to stdout to the common test framework 07923cc: [git] Don't spam to stdout in tests unless test failed 84a8fbe: [git] Fix already disposed 90d2f45: new inference: early abort calculation by lambda return (IDEA-124276) f2256ca: calculate target type in the same way for statement/expressions lambdas 896c488: testdata to expression lambda 8096d63: inference when incomplete 6f6367d: fix layout under darcula 3d3550e: escape ampersands 3768908: IDEA-123831 (Missing Method Count Limit in Inspections under Class Metrics) 04d3283: cleaning javac nametable: synchronization added 368bb54: [git tests] Better test name not to make some buildserver Gits "insane" ea6683d: [git tests] Better test dir name not to make some buildserver Gits "insane" 41d0942: remove unused properties [CR-IC-5247] cbf1c1e: ensure pushers are run before initial indexing, don't rely on chance 4c1dc50: let PushedFilePropertiesUpdater schedule reindex itself if necessary 79a75f2: update language level without project reloading 64c452e: Merge remote-tracking branch 'origin/master' b86dec4: simplify 0c0fb61: change method name ad18e4b: make method name discoverable 5529054: IDEA-124653 Keyboard shortcut for New does not work 3b7d2e9: svn: Refactored IdeaSvnkitBasedAuthenticationCallback - inner classes moved to separate files dafd2d3: revert memory page size back d5a0f9e: svn: Moved several authentication-related classes to "org.jetbrains.idea.svn.auth" package ac99e82: svn: Refactored IdeaSvnkitBasedAuthenticationCallback - made inner classes to be static e663caa: svn: Refactored IdeaSvnkitBasedAuthenticationCallback - code simplified, duplication removed 3ac7f7d: some dumb mode logging (IDEA-124604) 10bf86c: dom vfs listeners: don't load new vfs, support cyclic symlinks, simplify 2f76fdc: svn: Refactored IdeaSvnkitBasedAuthenticationCallback.AbstractAuthenticator and inheritors - code simplified ec05ae8: svn: Refactored IdeaSvnkitBasedAuthenticationCallback.AbstractAuthenticator and inheritors - common parameters moved to base class, @NotNull faf7595: ^451 add test 326278b: extract JsDebuggerViewSupport bc771e7: show data-source name for table editors 0faa413: making sure all posted tasks are processed even after process terminated and dispose called by using sequential task executor instead of MergingUpdateQueue (IDEA-120167 Phantom eternal Ant task on make) aff053d: Increase connection timeout for JIRA integration tests ab7c4be: WEB-6584 Files opened by URL should also be able to open scripts used in the file 1461ed0: cache indexOf result 8b73b26: cleanup 62b7621: svn: Refactored IdeaSvnkitBasedAuthenticationCallback.AbstractAuthenticator - made it not generic 6d7d17b: IDEA-124580 Links in mac sheets dialogs do not work 534c2aa: Temporary solution for IDEA-124615 cebe7d9: IDEA-124535 com.sun.*.internal packages not found 21110f2: moved to core d8cf8f5: @NotNull 979de11: moved to core-impl 9dd6e0d: moved to java-psi bf77b14: OriginInfoAwareElement moved to psi to core 26ef0e3: completion-related classes moved out of psi to separate package 4fe1761: removed dependency on java-impl 46408be: method references: super methods treatment in exact check a3f190a: svn: Refactored IdeaSvnkitBasedAuthenticationCallback.AbstractAuthenticator - removed unnecessary parameters from acknowledge() method 985bef3: Start plugins wizard #26 better color for selection (Darcula), hide dialog buttons when in "Customize plugin group" mode 4f97e92: Merge remote-tracking branch 'origin/master' 0081a7f: fixed PY-12819 Unable to run GAE nosetests 782ae0b: check directories consistency only for local files 95bce93: Cleanup (common URL check code extracted) 901e60d: Cleanup (arrangement; aggressive logging) d3d0f73: CaseInsensitiveUrlHashingStrategy nullability f144943: applicability constraints by method reference (IDEA-122018) 9e9c7e3: Cancel future if alarm was disposed in TaskItemProvider to prevent deadlocks 1e352af: Update CA certificate for SSL tests. Add link to test server used for client authentication 9ebf7ca: reparse files on language level change 29a7c80: will explicit System.gc lead to less ResolveClassTest blinking? ea54399: less garbage in tests (VirtualDirectoryImpl.assertConsistency) fba7ee7: postfix templates memory leak eb639ae: Merge remote-tracking branch 'origin/master' c5d0d5e: handle hidden groups correctly 0d2fc45: Merge remote-tracking branch 'origin/master' 577cef9: cleanup d14900f: svn: Refactored IdeaSvnkitBasedAuthenticationCallback - removed unused methods related to saving proxy settings to svn config files (currently proxy settings are passed through command line arguments) dedc16a: svn: Refactored IdeaSvnkitBasedAuthenticationCallback - code simplifications, @NotNull ef226f6: restore extra space trimmed by fitInsideEditor() 779ebf1: save some invokeLater's in progress text2 updating 9c46a51: Cleanup (arrangement; warns in default logger) b02b4c1: more accurate work with IOUtil.allocReadWriteBuffer: use IOUtil.write/readUTF that have thread local buffer upon softreference: - to avoid extra allocations (1G of garbage produced for our codebase indexing) - possible several threads accessing same buffer problem bb2af75: Cleanup (locale use) 949b567: IDEA-120035 (diagnostic; log level lowered) 4f1e8e6: svn: Refactored SvnAuthenticationManager - removed unused/commented code, code simplifications, warnings fixes 2fde908: WEB-11690 TypeScript breakpoint is not hit We must respect fs case sensitivity sourcemap visualizer: ugly compiler can produce mappings for empty lines, and IDEA can then strip whitespace from line ends, but sourcemap still references to empty ranges 81f903f: remove LineSeparatorPainter 902e51a: substitute bounds (IDEA-123509) 547c62c: qualify conflicting fields name (IDEA-123969) f58394c: IDEA-124019 291c431: notification group registration fixed f9f9b39: Merge remote-tracking branch 'origin/master' 527f8db: fireModelUpdate for lazy structure building (Scala, etc) f1c3652: IDEA-93452 Implement "section" support in rearrange menu: update parent offset on new section rule insert 47d8b3d: svn: Refactored MergeFromTheirsResolver - use common client factory model (instead of direct SVNWCClient usage) fe22b91: Fixed: IDEA-87312 Custom code folding: editor-fold; Folding/unfolding behavior not available when an enum inside the block IDEA-122715 Region folding does work if contains interface definition 4f9003f: Update jediterm.jar with antialiasing restored. 118d6d9: do not process xs:include for stub building ff22ffc: Fix tests 80dfa90: IDEA-93452 Implement "section" support in rearrange menu: section rules validation fe96f39: IDEA-124461 New Module (Maven, Gradle) created in Empty project don't get the specified jdk 1b8f51f: IDEA-124400 New Module wizard: Gradle module misses options 952a2c5: IDEA-71508 Scroll with inertia (Mac os) should only work in the initial component 632d4c8: don't draw separator line if we cannot compute relationship properly for all lines (important in case of process input — nodejs for example) 2ebc871: WEB-11957 Valid JavaScript regexp marked as red ca2c75e: svn: Refactored RepositoryBrowserDialog - removed unused and commented code a15d397: cleanup after adding postfix templates preview 7a06f6d: EA-56182 59454cd: improve "Show Members" opption suppression c115690: IDEA-124435 (Fix "Collapse catch blocks" produces non-compiling code) c048414: 136 -> 138 8c562a2: bug fix postfix templates preview 2b4b915: avoid wildcard with null bound (IDEA-124377) a6db438: testdata fixed a4ac655: Gradle: IDEA-124477 sourceFolder order in iml file generated by gradle is unstable c0f3611: IDEA-115374 "Print file" truncates the code on Mac 12a8f3b: Start plugins wizard #25 get rid of scrollpanes' borders ffe6776: A typo. 9fa19ab: svn: Refactored RepositoryBrowserDialog - make "move file/folder" logic use common client factory model (instead of direct SVNCopyClient usage) 7a95352: svn: Implemented ability to move files/folders directly in repository (for CopyMoveClient) 240c396: more diagnostics on EA-56168 - assert: JavaFoldingBuilderBase.addToFold ae954a6: remove unused ExtensionsArea.unregister* 3ad5dd7: Merge remote-tracking branch 'origin/master' 10fe5a5: skip symlinks ff8a795: removing -ea from defaults because this may dramatically slow down compilation (e.g. eclipse compiler with annotations): https://jetbrains.zendesk.com/agent/#/tickets/27833 a465476: HardReference for PsiAnchors used for duplicates indexing, 2 885405f: features.xml fix 016de10: Cleanup (inner class abuse) 58734a2: svn: Refactored RepositoryBrowserDialog - make file/folder deletion logic use common client factory model (instead of direct SVNCommitClient usage) 65fd69c: svn: Implemented ability to delete files/folders directly from repository (for DeleteClient) d9fe570: HardReference for PsiAnchors used for duplicates indexing 73a17e0: follow up for commit 288dd00: make util-rt available for all agents 55614bb: svn: Refactored RepositoryBrowserDialog - make folder creation logic use common client factory model (instead of direct SVNCommitClient usage) 7265d01: cleanup 10eb4a3: StartupManager: linear-time startup activities running 4708541: IDEA-124442 Update options for newer version of YourKit (get rid of deprecated warnings) e225a23: IDEA-124503 Filter out IntellijIdeaRulezzz completion items f41cb93: svn: Refactored CreateBranchOrTagAction - removed unnecessary parameters, removed todo items 54da0af: IDEA-122732 Javadoc invalid html closing tags b8197a7: OC-9621 d19a902: svn: Removed unused classes 924f108: svn: Refactored ShareProjectAction - use common client factory model (instead of direct SVNCommitClient usage) 673351f: svn: Implemented ability to create folders directly in repository (for BrowseClient) 8bd8a4d: initialize file watcher in background 9d3c23d: avoid entering dumb mode to push properties to one file 0ab0ec6: Maven: cleanup test e98a99f: Merge remote-tracking branch 'origin/master' bdfec0f: Mantis integration: Reset repository configuration on Axis errors 67cf17d: Maven: stable order of source folders IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates 5d0ce7c: enumerate items on demand c520519: Merge remote-tracking branch 'origin/master' c2957e7: anonymous -> lambda: conflicting ref in var declaration (IDEA-124525) 5dbbebe: extract superclass: process same name type parameters inside class members 84deec9: method refs: is exact should check super methods for this/super qualifiers only (IDEA-124507) 528a91b: Merge remote-tracking branch 'origin/master' 7a8f56c: fixed PY-12717 Improper replacement of the `print x, y` statement for Py3+ 33aeb0b: fixed PY-12804 PyStatementEffect inspection doesn't wrap exec argument in parenthesis 9929113: IDEA-124394 Exception while creating New File w/o extension 933194d: IDEA-124073 (avoid requesting focus manager until app is loaded) 4d43dab9: add before-after preview for postfix templates c4084ff: Merge remote-tracking branch 'origin/master' e2d7505: fixed PY-12726 PyCharm does not recognize compatibility issues when importing from __future__ 533e26d: do not reparse re-detected files in background in tests since it may cause unpleasant interference with e.g. highlighting 414c4ad: merged test classes ba23594: IDEA-124155 Performance problem on live search in long lines 6ce3483: Revert "Templates performance: run segments changes in bulk mode" c9284e0: Start plugins wizard #24 phrases 75472a5: calc hash from content once we have bytes available, don't delay its processing until we have only chars 5aac831: notnull 02a9c6e: notnull 81d2d98: cleanup 403d4f1: fix test a98abce: Templates performance: run segments changes in bulk mode 587e216: Merge remote-tracking branch 'origin/master' 66821eb: init WEB-11393 Live edit doesn't work for linked css 1429f44: IDEA-124527 Shift-drag after Shift-click starts new selection in editor d774199: IDEA-51883 IDEA prints out huge number of pages 8a80c54: Merge remote-tracking branch 'origin/master' 336be36: IDEA-98912 An Enter license button should be added to the welcome screen 72e2b3a: ensure each post-startup activity runs in smart mode (IDEA-123943) e64ae73: Merge remote-tracking branch 'origin/master' beeee74: make inspector work with modal dialogs 324ddc4: move getTokenType() up so white-spaces are skipped before rawTokenIndex() call c808c3e: integrate Grammar-Kit/pull/31 from ligasgr 984922a: tests fix afe050c: move xml lexers to gen root 2640f20: move groovy lexers to gen root eb2047f: move spi lexers to gen root cef748e: move java lexers to gen root 600887a: move reg exp lexer to gen root fc01dd0: move templates* lexers to gen root cbd64fa: move rest lexer to gen root fd2765c: move python-community lexers to gen root 90d1e84: more compact format when we serialize 8f3acde: use isjavaidentifierpart + enable trigramindex for tests because test appeared 2adc37a: IDEA-65879 "idea" protocol handler to open files directly from a URL (for Mac) 8615aa2: vfs: handling of invalid .jar files efb2fca: test framework: ability to intercept error/warn logs 0fff999: Groovy PSI doesn't depends on LookupElements anymore 92da487: some checkCanceled 876426a: magic constant b01adfe: know recursion manager deleted e9eaa2d: IDEA-124368 (diagnostic) d321dd2: vfs: JAR FS cleanup and minor optimization 4155907: revert IDEA-123049 Rearrange Code is breaking code (Code Style > Java > Arrangement) (1162eb1847279461e17d200416be100351d0c668) f62183c: IDEA-93452 Implement "section" support in rearrange menu: cleanup e833f18: Merge remote-tracking branch 'origin/master' a4f2f0e: create method from method ref: fis for type element qualifier (IDEA-124485) baccb31: diamonds: resolve conflicts based on type params from constructor and containing class (IDEA-123518) f3e1d96: IDEA-124385 1d32716: [by cdr, jeka] eliminating dependencies on utility classes in the code loaded by javac classloader to avoid NCDFE d08964e: IDEA-93452 Implement "section" support in rearrange menu. e16690a: better doctype detection 0645af6: move properties lexer to gen root e851587: svn: Refactored CreateBranchOrTagAction - do not create non-existent folders manually (as "svn copy" supports corresponding "--parents" option) 1162eb1: IDEA-123049 Rearrange Code is breaking code (Code Style > Java > Arrangement) 0c4028d: IDEA-123074 Code formatting. Closing brace. 7456ac5: svn: Use RA_ILLEGAL_URL error code for SVNException in command line info client when passed target does not exist (so CreateBranchOrTagAction.dirExists() works correctly for command line) 1dab5da: Maven: do not unexclude excludeFolders on removal of the respective physical directory related issue - IDEA-120944 Maven integration inconsistently, frequently, and spuriously changes .iml files 8be02cd: Allow to specify ranges which can't be indented by PostprocessReformattingAspect (fixes WI-22725 surround heredoc block with try catch causes parse error) [CR-IC-5135] 18bbc9d: IDEA-115374 "Print file" truncates the code on Mac 0d4ccd0: svn: Added ability to track warnings to SvnBindException 7ec9633: svn: Refactored SvnBindException - use MultiMap to track errors 820d7b2: Switcher: use TW stripe title instead of id 936b1f2: Merge remote-tracking branch 'origin/master' 0c1ec73: IDEA-124163 6fd9884: extract notification groups (IDEA-124454) 71f8a4a: IDEA-124352 b3926cf: EA-55442 - CCE: DomStubBuilder.buildStubTree - a better fix 370e06e: Merge remote-tracking branch 'origin/master' affac73: fixed PY-12731 Creating test profile from context menu unexpectedly creates django tests eed0df2: do not process xs:include for stub building 9bc7805: Revert "Do not wrap border with TitledBorder if there is not title" c255139: IDEA-119926 Completing Statements doesn't go to next line for non conditional statements 6988973: Ensure that indexes of substring are correct in YouTrackCompletionContributor ae4b79f: IDEA-112189 Change YouTrack integration default query 30c5366: MantisFilter violates comparable contact 2255513: svn: Moved execute() methods from CommandUtil to BaseSvnClient 46b8888: in django project show unittest runner and the django one in context menu 8bc1d46: Start plugins wizard #22 fix Windows-specific exceptions (non-initialized Alloy license & NPE during Darcula initialization) 42bc957: svn: Several classes moved to corresponding packages (commit related and exception classes) be188d5: Merge remote-tracking branch 'origin/master' 5e4c305: svn: "svn info" related classes moved to "org.jetbrains.idea.svn.info" package 19f9684: Start plugins wizard #20 icons for categories 93f8c1d: svn: Renamed info clients for both SVNKit and command line (interface and implementations) 063575b: svn: Make info clients (both for SVNKit and command line) satisfy common client factory model c0dd002: svn: Refactored SvnCommandLineInfoClient - do not inherit SvnkitSvnWcClient (just implement corresponding SvnWcClientI interface) 3dac920: svn: "svn status" related classes moved to "org.jetbrains.idea.svn.status" package 0d2131d: svn: Refactored CmdStatusClient - do not use CommandExecutor.myCommandLine directly (use corresponding CommandExecutor methods instead) 7b6f441: svn: Renamed status clients for both SVNKit and command line (interface and implementations) 7f65a87: fix for Kubuntu/Firefox/Gmail (IDEA-67767) 526a02f: fixed PY-12779 Configure Template directories quick-fix: open project structure settings page right away 9ee64e4: fix "go to source/type" — XSourcePosition doesn't provide column number, so, we must override createNavigatable 3f8277c: ability to invoke/reinvoke getter value a9663fe: Merge remote-tracking branch 'origin/master' 4ab4259: IDEA-123691 Minor project wizard edits: icons 16x16 b03f63d: fixed PY-12786 Python Interpreters: extra space in configuration popup from project creation dialog 546f9a5: Revert: IDEA-123160 Find Usages doing nothing in 13.1 (7371df17bd49da0804c600571671fd3a1fe90ec2) 3fbbef8: Merge remote-tracking branch 'origin/master' 2b99821: suppress project loading cancellation if in NonCancellableSection 25e6148: move PushedFilePropertiesUpdater to lang-impl 2782c66: semicolon->space in language-agnostic completion advertisement a9888bb: Merge remote-tracking branch 'origin/master' 779df06: fix messages d8f478c: changed to correct @NotNull 4f2dad1: EA-54648 - assert: PsiWalkingState.elementStarted 066ab8a: EA-55374 - NPE: DataFlowInspectionBase$.applyFix 16b53a5: EA-55442 - CCE: DomStubBuilder.buildStubTree 69fd8e8: EA-55457 - IE: CacheUpdateRunner.waitForAll 6b7c6a0: EA-55708 - NPE: FileEditorManager.getInstance d8e6415: [by cdr] optimizations d38a277: enabled by default c49c422: don't calc content hash id twice f82d4be: Merge remote-tracking branch 'origin/master' 4657702: Merge remote-tracking branch 'origin/master' b275b4e: Netty channel id init is not reliable yet 13aec5a: cleanup 5a75f21: continue WEB-9103 nodejs: show get/set functions in addition 72276e4: init WEB-9103 nodejs: Debugger not showing value of getter 029f89a: testdata fixed 03cba2c: add undo to JBTextField a344d0e: do not dbl substitution (type annotations could be lost after that) b898f91: static method reference completion (IDEA-124043) 78dafa0: dfa: just don't assume initialized final fields are notnull, it doesn't help, but hurts and slows things down (IDEA-124323) b6be84f: simplify HTML markup - updated test data (IDEA-67767) 622b745: simplify HTML markup (IDEA-67767) bcc4a00: junit category support (IDEA-88389) 99b16f3: check for project.isDisposed added to DumbService, unnecessary checks at call sites removed 3f304a3: Animator: test 36d9ddc: Animator: corereview CR-IC-5059 9709e9f: Animator: fix stuck at 0th frame during repeatable animaion 1957b85: SemVer.getParsedVersion added 8e48a46: SemVer.toString added ae2667d: Merge remote-tracking branch 'origin/master' 1be6001: fixed PY-12451 Interpreter added from project creation dialog is not set as project interpreter 5bb9964: fixed possible NPE 9359151: Platform: scrollbars survive background editors initialization 3ca40fc: fixed tests f2b136a: fixed possible NPE 8fde24a: drain file type queue 835ce62: cleanup f2fb07f: removed lang-impl dependency edb88b8: notnull 6dd81f8: NPE when application is already disposed c2545c2: unmute on session finish - spelling 223dffa: IDEA-122962 - Clouds: perform connection test in background 7cc9133: Merge remote-tracking branch 'origin/master' c5bffbd: remove duplicated code (IDEA-67767) a5a9d6a: Merge remote-tracking branch 'origin/master' 1167e96: fixed PY-12543 Project Interpreters: too big or too small details popup cbc40e9: lazy array data loading — API/UI/v8 new backend done WEB-11784 slow nodejs debug: huge array cause 100 cpu debug a892f89: add missing test data 2215544: fix another RTF background colouring issue (IDEA-67767) fd2b253: Merge remote-tracking branch 'origin/master' bc7a7ad: Merge remote-tracking branch 'origin/master' fda4b8a: Merge remote-tracking branch 'origin/master' c8474eb: fix testdata ee2a5d0: introduce: process chained method calls during same occurrences processing (IDEA-124349) 9397fb0: CR-IC-5167 (cleanup) 8dbf638: Cleanup (post-review #330) 91e3ed4: vfs: .jar refresh test extended 115aaf1: vfs: unified attributes loading between JarHandler / JarFS 10efd8b: Cleanup (duplication; readability) 8231d80: IDEA-124032 IDEA plugin: Can't find com.sun.xml.internal.messaging.saaj.soap.LocalStrings bundle: allow bootstrap resources for root IDEA classloader cb808a6: fixed PY-12723 Unable to run tests with Django 1.7b1: "RuntimeError: App registry isn't ready yet." 8c5c0ec: added project.isDisposed check to DumbService 1f2a568: code style 46881e4: Merge remote-tracking branch 'origin/master' 8401fa0: fixed windows path separator 6ae658f: fixed 'project is disposed' 6431234: Github: release editor in tests c726c53: Github: small test cleanup 6d6d583: Platform: ShowFilePathAction correctly handles non-normalized paths (e.g. with ../) 8e1f7a7: Merge remote-tracking branch 'origin/master' 916d90b: Platform: always allow writing module files (IDEA-123899) + typo in test fixed 6e063ee: IDEA-121318 ClosureParamsEnhancer now uses call.getCallVariants() instead of call.resolve(). Erasing instance parameter's types when comparing them. It helps to select the correct one when we are comparing T and Iterable<T>. 637da92: IDEA-123712 Groovy: @language annotation on method parameters with default values reflected methods now have light parameters with original modifier lists 8ffcef2: EA-52671 - assert: AbstractMappingStrategy.processFoldRegion 30d14a3: fix RTF background colouring and make it compatible with Mac (IDEA-67767) 39d7edd: svn: Make status clients (both for SVNKit and command line) satisfy common client factory model 85e3825: Merge remote-tracking branch 'origin/master' 1d31c68: svn: Refactored SvnRecursiveStatusWalker.MyItem - use common client factory model (instead of direct SVNStatusClient usage) 3a14f0a: Use tree set to store remote roots to avoid duplicates. 343ea1c: svn: Refactored SvnRecursiveStatusWalker - methods extracted, warnings fixes 3ca64b6: svn: Merged StatusWalkerPartner interface and StatusWalkerPartnerImpl implementation to single class 93ddbc2: svn: Refactored SvnChangeProvider - use common client factory model (instead of direct SVNStatusClient usage) 416463d: svn: Refactored SvnRecursiveStatusWalker.MyItem.getClient() - removed unnecessary parameters 82af9cb: svn: SvnCommitRunner moved to "checkin" package and renamed b0b7121: svn: Refactored SvnCheckinEnvironment - logic extracted to separate SVNKit and command line clients (common client factory model is used) af5ad7c: svn: Refactored SvnCommitRunner - inlined several parameters (that have same value in all code paths) beb8081: svn: Refactored SvnCheckinEnvironment - moved SVNKit related logic to corresponding SVNKit-scoped method 626d944: svn: Refactored SvnCheckinEnvironment - code simplified, unified code flows for SVNKit and command line c636313: IDEA-124057 Manually load key store set using VM options. Don't modify default context, if Certificate Manager was disabled 4729cf2: svn: Refactored OneShotMergeInfoHelper and OneRecursiveShotMergeInfoWorker - removed unnecessary fields and utilize MergeContext instead 9fe9ac9: svn: Refactored LoadRecentBranchRevisions - removed unnecessary fields and utilize MergeContext instead 562e89d: svn: Refactored MergeCalculatorTask - removed unnecessary fields and utilize data from MergeContext instead c85e79d: svn: Refactored QuickMerge - inner classes moved to separate files (and renamed) 3f10457: IDEA-122845 Add test to check that wrong credentials are recognized when testConnection() is used cf3252c: svn: Refactored QuickMerge - make task classes do not directly depend on QuickMerge instance * MergeContext and QuickMergeInteraction parameters added to all task constructors * several QuickMerge methods moved to corresponding task classes e62ad72: svn: Refactored QuickMerge - merge parameters extracted to separate MergeContext class 482733a: svn: Refactored LatestExistentSearcher - use common client factory model (instead of direct SVNLogClient usage) a260ac4: svn: Refactored DefaultConfigLoader - code simplifications, warnings fixes d899191: svn: Make sure start() method of the task queue (myBranchesLoader) in SvnBranchConfigurationManager is invoked - otherwise runnables passed to queue are not executed a95c8b4: svn: Refactored DefaultConfigLoader - use common client factory model (instead of direct SVNLogClient usage) 1d33a57: svn: Refactored FirstInBranch - use common client factory model (instead of direct SVNLogClient usage) 372a664: svn: Refactored SvnMergeInfoCache - removed inner MyState class (fields added directly to SvnMergeInfoCache) 281cc56: svn: Refactored FirstInBranch - not null, code simplifications (exception handling) ef8bad7: svn: Refactored FirstInBranch - code simplifications, warnings fixes 2104741: svn: Removed unnecessary SvnBranchPointsCalculator.Invertor interface 0b9815c: svn: Refactored SvnBranchPointsCalculator.WrapperInvertor - explicitly use SvnBranchPointsCalculator.BranchCopyData type (instead of being generic) aa5e3fd: svn: Refactored MergerFactory - removed unused methods 9d618f1: svn: Refactored SvnMergeInfoTest - methods extracted, duplication removed, warning fixes 4947243: svn: Refactored SvnMergeInfoTest - methods extracted, lots of duplication removed Change-Id: Id231a4e5444690193a99f454d027ea17f7c2845c
Diffstat (limited to 'python/helpers/pydev')
-rw-r--r--python/helpers/pydev/_pydev_completer.py (renamed from python/helpers/pydev/_completer.py)50
-rw-r--r--python/helpers/pydev/_pydev_execfile.py3
-rw-r--r--python/helpers/pydev/_pydev_filesystem_encoding.py39
-rw-r--r--python/helpers/pydev/_pydev_imports_tipper.py (renamed from python/helpers/pydev/importsTipper.py)6
-rw-r--r--python/helpers/pydev/_pydev_jy_imports_tipper.py (renamed from python/helpers/pydev/jyimportsTipper.py)2
-rw-r--r--python/helpers/pydev/_pydev_tipper_common.py (renamed from python/helpers/pydev/_tipper_common.py)0
-rw-r--r--python/helpers/pydev/_pydev_xmlrpc_hook.py74
-rw-r--r--python/helpers/pydev/django_frame.py12
-rw-r--r--python/helpers/pydev/interpreterInfo.py233
-rw-r--r--python/helpers/pydev/pycompletion.py6
-rw-r--r--python/helpers/pydev/pycompletionserver.py316
-rw-r--r--python/helpers/pydev/pydev_app_engine_debug_startup.py21
-rw-r--r--python/helpers/pydev/pydev_console_utils.py103
-rw-r--r--python/helpers/pydev/pydev_imports.py59
-rw-r--r--python/helpers/pydev/pydev_ipython/README8
-rw-r--r--python/helpers/pydev/pydev_ipython/__init__.py0
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhook.py525
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookglut.py153
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookgtk.py36
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookgtk3.py35
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookpyglet.py92
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookqt4.py194
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhooktk.py23
-rw-r--r--python/helpers/pydev/pydev_ipython/inputhookwx.py167
-rw-r--r--python/helpers/pydev/pydev_ipython/qt.py23
-rw-r--r--python/helpers/pydev/pydev_ipython/qt_for_kernel.py83
-rw-r--r--python/helpers/pydev/pydev_ipython/qt_loaders.py258
-rw-r--r--python/helpers/pydev/pydev_ipython/version.py36
-rw-r--r--python/helpers/pydev/pydev_ipython_console.py2
-rw-r--r--python/helpers/pydev/pydev_ipython_console_011.py18
-rw-r--r--python/helpers/pydev/pydev_versioncheck.py16
-rw-r--r--python/helpers/pydev/pydevconsole.py49
-rw-r--r--python/helpers/pydev/pydevd.py610
-rw-r--r--python/helpers/pydev/pydevd_additional_thread_info.py8
-rw-r--r--python/helpers/pydev/pydevd_comm.py213
-rw-r--r--python/helpers/pydev/pydevd_constants.py47
-rw-r--r--python/helpers/pydev/pydevd_custom_frames.py121
-rw-r--r--python/helpers/pydev/pydevd_exec.py7
-rw-r--r--python/helpers/pydev/pydevd_exec2.py7
-rw-r--r--python/helpers/pydev/pydevd_frame.py80
-rw-r--r--python/helpers/pydev/pydevd_import_class.py2
-rw-r--r--python/helpers/pydev/pydevd_io.py20
-rw-r--r--python/helpers/pydev/pydevd_reload.py611
-rw-r--r--python/helpers/pydev/pydevd_resolver.py92
-rw-r--r--python/helpers/pydev/pydevd_save_locals.py58
-rw-r--r--python/helpers/pydev/pydevd_stackless.py412
-rw-r--r--python/helpers/pydev/pydevd_tracing.py9
-rw-r--r--python/helpers/pydev/pydevd_vars.py132
-rw-r--r--python/helpers/pydev/pydevd_xml.py28
49 files changed, 4225 insertions, 874 deletions
diff --git a/python/helpers/pydev/_completer.py b/python/helpers/pydev/_pydev_completer.py
index 4d34fec2d1ae..93e0bfa3969f 100644
--- a/python/helpers/pydev/_completer.py
+++ b/python/helpers/pydev/_pydev_completer.py
@@ -1,3 +1,4 @@
+import pydevconsole
try:
import __builtin__
@@ -13,13 +14,14 @@ except NameError: # version < 2.3 -- didn't have the True/False builtins
try:
import java.lang #@UnusedImport
- import jyimportsTipper #as importsTipper #changed to be backward compatible with 1.5
- importsTipper = jyimportsTipper
+ import _pydev_jy_imports_tipper #as _pydev_imports_tipper #changed to be backward compatible with 1.5
+ _pydev_imports_tipper = _pydev_jy_imports_tipper
except ImportError:
IS_JYTHON = False
- import importsTipper
+ import _pydev_imports_tipper
-dir2 = importsTipper.GenerateImportsTipForModule
+import pydevd_vars
+dir2 = _pydev_imports_tipper.GenerateImportsTipForModule
#=======================================================================================================================
@@ -153,3 +155,43 @@ class Completer:
return words
+#=======================================================================================================================
+# GenerateCompletionsAsXML
+#=======================================================================================================================
+def GenerateCompletionsAsXML(frame, act_tok):
+ if frame is None:
+ return '<xml></xml>'
+
+ #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
+ #(Names not resolved in generator expression in method)
+ #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
+ updated_globals = {}
+ updated_globals.update(frame.f_globals)
+ updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
+
+ if pydevconsole.IPYTHON:
+ completions = pydevconsole.get_completions(act_tok, act_tok, updated_globals, frame.f_locals)
+ else:
+ completer = Completer(updated_globals, None)
+ #list(tuple(name, descr, parameters, type))
+ completions = completer.complete(act_tok)
+
+ valid_xml = pydevd_vars.makeValidXmlValue
+ quote = pydevd_vars.quote
+
+ msg = ["<xml>"]
+
+ for comp in completions:
+ msg.append('<comp p0="')
+ msg.append(valid_xml(quote(comp[0], '/>_= \t')))
+ msg.append('" p1="')
+ msg.append(valid_xml(quote(comp[1], '/>_= \t')))
+ msg.append('" p2="')
+ msg.append(valid_xml(quote(comp[2], '/>_= \t')))
+ msg.append('" p3="')
+ msg.append(valid_xml(quote(comp[3], '/>_= \t')))
+ msg.append('"/>')
+ msg.append("</xml>")
+
+ return ''.join(msg)
+
diff --git a/python/helpers/pydev/_pydev_execfile.py b/python/helpers/pydev/_pydev_execfile.py
index 1d8e141371de..d60d7ed94bb0 100644
--- a/python/helpers/pydev/_pydev_execfile.py
+++ b/python/helpers/pydev/_pydev_execfile.py
@@ -1,7 +1,8 @@
#We must redefine it in Py3k if it's not already there
def execfile(file, glob=None, loc=None):
if glob is None:
- glob = globals()
+ import sys
+ glob = sys._getframe().f_back.f_globals
if loc is None:
loc = glob
stream = open(file, 'rb')
diff --git a/python/helpers/pydev/_pydev_filesystem_encoding.py b/python/helpers/pydev/_pydev_filesystem_encoding.py
new file mode 100644
index 000000000000..670625fe0c0f
--- /dev/null
+++ b/python/helpers/pydev/_pydev_filesystem_encoding.py
@@ -0,0 +1,39 @@
+def __getfilesystemencoding():
+ '''
+ Note: there's a copy of this method in interpreterInfo.py
+ '''
+ import sys
+ try:
+ ret = sys.getfilesystemencoding()
+ if not ret:
+ raise RuntimeError('Unable to get encoding.')
+ return ret
+ except:
+ try:
+ #Handle Jython
+ from java.lang import System
+ env = System.getProperty("os.name").lower()
+ if env.find('win') != -1:
+ return 'ISO-8859-1' #mbcs does not work on Jython, so, use a (hopefully) suitable replacement
+ return 'utf-8'
+ except:
+ pass
+
+ #Only available from 2.3 onwards.
+ if sys.platform == 'win32':
+ return 'mbcs'
+ return 'utf-8'
+
+def getfilesystemencoding():
+ try:
+ ret = __getfilesystemencoding()
+
+ #Check if the encoding is actually there to be used!
+ if hasattr('', 'encode'):
+ ''.encode(ret)
+ if hasattr('', 'decode'):
+ ''.decode(ret)
+
+ return ret
+ except:
+ return 'utf-8'
diff --git a/python/helpers/pydev/importsTipper.py b/python/helpers/pydev/_pydev_imports_tipper.py
index 97fc76a91b3e..e4b3b863f210 100644
--- a/python/helpers/pydev/importsTipper.py
+++ b/python/helpers/pydev/_pydev_imports_tipper.py
@@ -2,7 +2,7 @@ import os.path
import inspect
import sys
-from _tipper_common import DoFind
+from _pydev_tipper_common import DoFind
#completion types.
@@ -151,7 +151,9 @@ def GenerateImportsTipForModule(obj_to_complete, dirComps=None, getattr=getattr,
dirComps = dir(obj_to_complete)
if hasattr(obj_to_complete, '__dict__'):
dirComps.append('__dict__')
-
+ if hasattr(obj_to_complete, '__class__'):
+ dirComps.append('__class__')
+
getCompleteInfo = True
if len(dirComps) > 1000:
diff --git a/python/helpers/pydev/jyimportsTipper.py b/python/helpers/pydev/_pydev_jy_imports_tipper.py
index cd8da2614357..43e4d0b67140 100644
--- a/python/helpers/pydev/jyimportsTipper.py
+++ b/python/helpers/pydev/_pydev_jy_imports_tipper.py
@@ -4,7 +4,7 @@ from java.lang import StringBuffer #@UnresolvedImport
from java.lang import String #@UnresolvedImport
import java.lang #@UnresolvedImport
import sys
-from _tipper_common import DoFind
+from _pydev_tipper_common import DoFind
try:
diff --git a/python/helpers/pydev/_tipper_common.py b/python/helpers/pydev/_pydev_tipper_common.py
index f8c46d232b10..f8c46d232b10 100644
--- a/python/helpers/pydev/_tipper_common.py
+++ b/python/helpers/pydev/_pydev_tipper_common.py
diff --git a/python/helpers/pydev/_pydev_xmlrpc_hook.py b/python/helpers/pydev/_pydev_xmlrpc_hook.py
new file mode 100644
index 000000000000..22d445a0c867
--- /dev/null
+++ b/python/helpers/pydev/_pydev_xmlrpc_hook.py
@@ -0,0 +1,74 @@
+from pydev_imports import SimpleXMLRPCServer
+from pydev_ipython.inputhook import get_inputhook, set_return_control_callback
+import select
+import sys
+
+select_fn = select.select
+if sys.platform.startswith('java'):
+ select_fn = select.cpython_compatible_select
+
+class InputHookedXMLRPCServer(SimpleXMLRPCServer):
+ ''' An XML-RPC Server that can run hooks while polling for new requests.
+
+ This code was designed to work with IPython's inputhook methods and
+ to allow Debug framework to have a place to run commands during idle
+ too.
+ '''
+ def __init__(self, *args, **kwargs):
+ SimpleXMLRPCServer.__init__(self, *args, **kwargs)
+ # Tell the inputhook mechanisms when control should be returned
+ set_return_control_callback(self.return_control)
+ self.debug_hook = None
+ self.return_control_osc = False
+
+ def return_control(self):
+ ''' A function that the inputhooks can call (via inputhook.stdin_ready()) to find
+ out if they should cede control and return '''
+ if self.debug_hook:
+ # Some of the input hooks check return control without doing
+ # a single operation, so we don't return True on every
+ # call when the debug hook is in place to allow the GUI to run
+ # XXX: Eventually the inputhook code will have diverged enough
+ # from the IPython source that it will be worthwhile rewriting
+ # it rather than pretending to maintain the old API
+ self.return_control_osc = not self.return_control_osc
+ if self.return_control_osc:
+ return True
+ r, unused_w, unused_e = select_fn([self], [], [], 0)
+ return bool(r)
+
+ def setDebugHook(self, debug_hook):
+ self.debug_hook = debug_hook
+
+ def serve_forever(self):
+ ''' Serve forever, running defined hooks regularly and when idle.
+ Does not support shutdown '''
+ inputhook = get_inputhook()
+ while True:
+ # Block for default 1/2 second when no GUI is in progress
+ timeout = 0.5
+ if self.debug_hook:
+ self.debug_hook()
+ timeout = 0.1
+ if inputhook:
+ try:
+ inputhook()
+ # The GUI has given us an opportunity to try receiving, normally
+ # this happens because the input hook has already polled the
+ # server has knows something is waiting
+ timeout = 0.020
+ except:
+ inputhook = None
+ r, unused_w, unused_e = select_fn([self], [], [], timeout)
+ if self in r:
+ try:
+ self._handle_request_noblock()
+ except AttributeError:
+ # Older libraries do not support _handle_request_noblock, so fall
+ # back to the handle_request version
+ self.handle_request()
+ # Running the request may have changed the inputhook in use
+ inputhook = get_inputhook()
+
+ def shutdown(self):
+ raise NotImplementedError('InputHookedXMLRPCServer does not support shutdown')
diff --git a/python/helpers/pydev/django_frame.py b/python/helpers/pydev/django_frame.py
index 272888e26d16..762df2d16579 100644
--- a/python/helpers/pydev/django_frame.py
+++ b/python/helpers/pydev/django_frame.py
@@ -30,7 +30,7 @@ def offset_to_line_number(text, offset):
def get_source(frame):
try:
- node = frame.f_locals['self']
+ node = frame.f_locals['self']
if hasattr(node, 'source'):
return node.source
else:
@@ -49,9 +49,13 @@ def get_template_file_name(frame):
pydev_log.debug("Source is None\n")
return None
fname = source[0].name
- pydev_log.debug("Source name is %s\n" % fname)
- filename, base = GetFileNameAndBaseFromFile(fname)
- return filename
+
+ if fname == '<unknown source>':
+ pydev_log.debug("Source name is %s\n" % fname)
+ return None
+ else:
+ filename, base = GetFileNameAndBaseFromFile(fname)
+ return filename
except:
pydev_log.debug(traceback.format_exc())
return None
diff --git a/python/helpers/pydev/interpreterInfo.py b/python/helpers/pydev/interpreterInfo.py
index f6056d0de60e..103253e62600 100644
--- a/python/helpers/pydev/interpreterInfo.py
+++ b/python/helpers/pydev/interpreterInfo.py
@@ -6,138 +6,247 @@ what is what:
sys.builtin_module_names: contains the builtin modules embeeded in python (rigth now, we specify all manually).
sys.prefix: A string giving the site-specific directory prefix where the platform independent Python files are installed
-format is something as
+format is something as
EXECUTABLE:python.exe|libs@compiled_dlls$builtin_mods
all internal are separated by |
'''
import sys
-import os
+try:
+ import os.path
+ def fullyNormalizePath(path):
+ '''fixes the path so that the format of the path really reflects the directories in the system
+ '''
+ return os.path.normpath(path)
+ join = os.path.join
+except: # ImportError or AttributeError.
+ # See: http://stackoverflow.com/questions/10254353/error-while-installing-jython-for-pydev
+ def fullyNormalizePath(path):
+ '''fixes the path so that the format of the path really reflects the directories in the system
+ '''
+ return path
+
+ def join(a, b):
+ if a.endswith('/') or a.endswith('\\'):
+ return a + b
+ return a + '/' + b
+
+
+IS_PYTHON_3K = 0
+
+try:
+ if sys.version_info[0] == 3:
+ IS_PYTHON_3K = 1
+except:
+ # That's OK, not all versions of python have sys.version_info
+ pass
try:
- #Just check if False and True are defined (depends on version, not whether it's jython/python)
+ # Just check if False and True are defined (depends on version, not whether it's jython/python)
False
True
except:
- exec ('True, False = 1,0') #An exec is used so that python 3k does not give a syntax error
-
-import pydevd_constants
-
-if pydevd_constants.USE_LIB_COPY:
- import _pydev_time as time
-else:
- import time
+ exec ('True, False = 1,0') # An exec is used so that python 3k does not give a syntax error
if sys.platform == "cygwin":
-
+
try:
- import ctypes #use from the system if available
+ import ctypes # use from the system if available
except ImportError:
- sys.path.append(os.path.join(sys.path[0], 'ThirdParty/wrapped_for_pydev'))
+ sys.path.append(join(sys.path[0], 'third_party/wrapped_for_pydev'))
import ctypes
-
+
def nativePath(path):
MAX_PATH = 512 # On cygwin NT, its 260 lately, but just need BIG ENOUGH buffer
'''Get the native form of the path, like c:\\Foo for /cygdrive/c/Foo'''
retval = ctypes.create_string_buffer(MAX_PATH)
path = fullyNormalizePath(path)
- ctypes.cdll.cygwin1.cygwin_conv_to_win32_path(path, retval) #@UndefinedVariable
- return retval.value
+ CCP_POSIX_TO_WIN_A = 0
+ ctypes.cdll.cygwin1.cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, retval, MAX_PATH)
+ return retval.value
+
else:
def nativePath(path):
return fullyNormalizePath(path)
-
-def fullyNormalizePath(path):
- '''fixes the path so that the format of the path really reflects the directories in the system
+
+
+
+def __getfilesystemencoding():
+ '''
+ Note: there's a copy of this method in _pydev_filesystem_encoding.py
'''
- return os.path.normpath(path)
+ try:
+ ret = sys.getfilesystemencoding()
+ if not ret:
+ raise RuntimeError('Unable to get encoding.')
+ return ret
+ except:
+ try:
+ # Handle Jython
+ from java.lang import System
+ env = System.getProperty("os.name").lower()
+ if env.find('win') != -1:
+ return 'ISO-8859-1' # mbcs does not work on Jython, so, use a (hopefully) suitable replacement
+ return 'utf-8'
+ except:
+ pass
+
+ # Only available from 2.3 onwards.
+ if sys.platform == 'win32':
+ return 'mbcs'
+ return 'utf-8'
+
+def getfilesystemencoding():
+ try:
+ ret = __getfilesystemencoding()
+
+ #Check if the encoding is actually there to be used!
+ if hasattr('', 'encode'):
+ ''.encode(ret)
+ if hasattr('', 'decode'):
+ ''.decode(ret)
+
+ return ret
+ except:
+ return 'utf-8'
+
+file_system_encoding = getfilesystemencoding()
+
+def tounicode(s):
+ if hasattr(s, 'decode'):
+ # Depending on the platform variant we may have decode on string or not.
+ return s.decode(file_system_encoding)
+ return s
+
+def toutf8(s):
+ if hasattr(s, 'encode'):
+ return s.encode('utf-8')
+ return s
+
+def toasciimxl(s):
+ # output for xml without a declared encoding
+
+ # As the output is xml, we have to encode chars (< and > are ok as they're not accepted in the filesystem name --
+ # if it was allowed, we'd have to do things more selectively so that < and > don't get wrongly replaced).
+ s = s.replace("&", "&amp;")
+
+ try:
+ ret = s.encode('ascii', 'xmlcharrefreplace')
+ except:
+ # use workaround
+ ret = ''
+ for c in s:
+ try:
+ ret += c.encode('ascii')
+ except:
+ try:
+ # Python 2: unicode is a valid identifier
+ ret += unicode("&#%d;") % ord(c)
+ except:
+ # Python 3: a string is already unicode, so, just doing it directly should work.
+ ret += "&#%d;" % ord(c)
+ return ret
if __name__ == '__main__':
try:
- #just give some time to get the reading threads attached (just in case)
+ # just give some time to get the reading threads attached (just in case)
+ import time
time.sleep(0.1)
except:
pass
-
+
try:
executable = nativePath(sys.executable)
except:
executable = sys.executable
-
+
if sys.platform == "cygwin" and not executable.endswith('.exe'):
executable += '.exe'
-
+
try:
- s = 'Version%s.%s' % (sys.version_info[0], sys.version_info[1])
+ major = str(sys.version_info[0])
+ minor = str(sys.version_info[1])
except AttributeError:
- #older versions of python don't have version_info
+ # older versions of python don't have version_info
import string
s = string.split(sys.version, ' ')[0]
s = string.split(s, '.')
major = s[0]
minor = s[1]
- s = 'Version%s.%s' % (major, minor)
-
- sys.stdout.write('%s\n' % (s,))
-
- sys.stdout.write('EXECUTABLE:%s|\n' % executable)
-
- #this is the new implementation to get the system folders
- #(still need to check if it works in linux)
- #(previously, we were getting the executable dir, but that is not always correct...)
- prefix = nativePath(sys.prefix)
- #print_ 'prefix is', prefix
-
+
+ s = tounicode('%s.%s') % (tounicode(major), tounicode(minor))
+
+ contents = [tounicode('<xml>')]
+ contents.append(tounicode('<version>%s</version>') % (tounicode(s),))
+
+ contents.append(tounicode('<executable>%s</executable>') % tounicode(executable))
+
+ # this is the new implementation to get the system folders
+ # (still need to check if it works in linux)
+ # (previously, we were getting the executable dir, but that is not always correct...)
+ prefix = tounicode(nativePath(sys.prefix))
+ # print_ 'prefix is', prefix
+
result = []
-
+
path_used = sys.path
try:
- path_used = path_used[:] #Use a copy.
+ path_used = path_used[1:] # Use a copy (and don't include the directory of this script as a path.)
except:
- pass #just ignore it...
-
+ pass # just ignore it...
+
for p in path_used:
- p = nativePath(p)
-
+ p = tounicode(nativePath(p))
+
try:
- import string #to be compatible with older versions
- if string.find(p, prefix) == 0: #was startswith
+ import string # to be compatible with older versions
+ if string.find(p, prefix) == 0: # was startswith
result.append((p, True))
else:
result.append((p, False))
except (ImportError, AttributeError):
- #python 3k also does not have it
- #jython may not have it (depending on how are things configured)
- if p.startswith(prefix): #was startswith
+ # python 3k also does not have it
+ # jython may not have it (depending on how are things configured)
+ if p.startswith(prefix): # was startswith
result.append((p, True))
else:
result.append((p, False))
-
+
for p, b in result:
if b:
- sys.stdout.write('|%s%s\n' % (p, 'INS_PATH'))
+ contents.append(tounicode('<lib path="ins">%s</lib>') % (p,))
else:
- sys.stdout.write('|%s%s\n' % (p, 'OUT_PATH'))
-
- sys.stdout.write('@\n') #no compiled libs
- sys.stdout.write('$\n') #the forced libs
-
+ contents.append(tounicode('<lib path="out">%s</lib>') % (p,))
+
+ # no compiled libs
+ # nor forced libs
+
for builtinMod in sys.builtin_module_names:
- sys.stdout.write('|%s\n' % builtinMod)
-
-
+ contents.append(tounicode('<forced_lib>%s</forced_lib>') % tounicode(builtinMod))
+
+
+ contents.append(tounicode('</xml>'))
+ unic = tounicode('\n').join(contents)
+ inasciixml = toasciimxl(unic)
+ if IS_PYTHON_3K:
+ # This is the 'official' way of writing binary output in Py3K (see: http://bugs.python.org/issue4571)
+ sys.stdout.buffer.write(inasciixml)
+ else:
+ sys.stdout.write(inasciixml)
+
try:
sys.stdout.flush()
sys.stderr.flush()
- #and give some time to let it read things (just in case)
+ # and give some time to let it read things (just in case)
+ import time
time.sleep(0.1)
except:
pass
-
+
raise RuntimeError('Ok, this is so that it shows the output (ugly hack for some platforms, so that it releases the output).')
diff --git a/python/helpers/pydev/pycompletion.py b/python/helpers/pydev/pycompletion.py
index 93dd2e85598c..e706d5410f3d 100644
--- a/python/helpers/pydev/pycompletion.py
+++ b/python/helpers/pydev/pycompletion.py
@@ -2,10 +2,12 @@
'''
@author Radim Kubacki
'''
-import importsTipper
+import __builtin__
+import _pydev_imports_tipper
import traceback
import StringIO
import sys
+import time
import urllib
import pycompletionserver
@@ -17,7 +19,7 @@ def GetImports(module_name):
try:
processor = pycompletionserver.Processor()
data = urllib.unquote_plus(module_name)
- def_file, completions = importsTipper.GenerateTip(data)
+ def_file, completions = _pydev_imports_tipper.GenerateTip(data)
return processor.formatCompletionMessage(def_file, completions)
except:
s = StringIO.StringIO()
diff --git a/python/helpers/pydev/pycompletionserver.py b/python/helpers/pydev/pycompletionserver.py
index fc4332f75f0d..2fdd53903fb1 100644
--- a/python/helpers/pydev/pycompletionserver.py
+++ b/python/helpers/pydev/pycompletionserver.py
@@ -1,20 +1,20 @@
#@PydevCodeAnalysisIgnore
'''
-@author Fabio Zadrozny
+@author Fabio Zadrozny
'''
IS_PYTHON3K = 0
try:
import __builtin__
except ImportError:
- import builtins as __builtin__ # Python 3.0
+ import builtins as __builtin__ # Python 3.0
IS_PYTHON3K = 1
try:
- True
- False
-except NameError:
- #If it's not defined, let's define it now.
- setattr(__builtin__, 'True', 1) #Python 3.0 does not accept __builtin__.True = 1 in its syntax
+ True
+ False
+except NameError:
+ # If it's not defined, let's define it now.
+ setattr(__builtin__, 'True', 1) # Python 3.0 does not accept __builtin__.True = 1 in its syntax
setattr(__builtin__, 'False', 0)
import pydevd_constants
@@ -23,18 +23,18 @@ try:
from java.lang import Thread
IS_JYTHON = True
SERVER_NAME = 'jycompletionserver'
- import jyimportsTipper #as importsTipper #changed to be backward compatible with 1.5
- importsTipper = jyimportsTipper
+ import _pydev_jy_imports_tipper # as _pydev_imports_tipper #changed to be backward compatible with 1.5
+ _pydev_imports_tipper = _pydev_jy_imports_tipper
except ImportError:
- #it is python
+ # it is python
IS_JYTHON = False
SERVER_NAME = 'pycompletionserver'
if pydevd_constants.USE_LIB_COPY:
from _pydev_threading import Thread
else:
from threading import Thread
- import importsTipper
+ import _pydev_imports_tipper
if pydevd_constants.USE_LIB_COPY:
@@ -44,20 +44,20 @@ else:
import sys
if sys.platform == "darwin":
- #See: https://sourceforge.net/projects/pydev/forums/forum/293649/topic/3454227
+ # See: https://sourceforge.net/projects/pydev/forums/forum/293649/topic/3454227
try:
- import _CF #Don't fail if it doesn't work.
+ import _CF # Don't fail if it doesn't work -- do it because it must be loaded on the main thread! @UnresolvedImport @UnusedImport
except:
pass
-#initial sys.path
+# initial sys.path
_sys_path = []
for p in sys.path:
- #changed to be compatible with 1.5
+ # changed to be compatible with 1.5
_sys_path.append(p)
-#initial sys.modules
+# initial sys.modules
_sys_modules = {}
for name, mod in sys.modules.items():
_sys_modules[name] = mod
@@ -104,12 +104,10 @@ MSG_INVALID_REQUEST = '@@INVALID_REQUEST'
MSG_JYTHON_INVALID_REQUEST = '@@JYTHON_INVALID_REQUEST'
MSG_CHANGE_DIR = '@@CHANGE_DIR:'
MSG_OK = '@@MSG_OK_END@@'
-MSG_BIKE = '@@BIKE'
-MSG_PROCESSING = '@@PROCESSING_END@@'
-MSG_PROCESSING_PROGRESS = '@@PROCESSING:%sEND@@'
MSG_IMPORTS = '@@IMPORTS:'
MSG_PYTHONPATH = '@@PYTHONPATH_END@@'
MSG_CHANGE_PYTHONPATH = '@@CHANGE_PYTHONPATH:'
+MSG_JEDI = '@@MSG_JEDI:'
MSG_SEARCH = '@@SEARCH'
BUFFER_SIZE = 1024
@@ -118,74 +116,46 @@ BUFFER_SIZE = 1024
currDirModule = None
-def CompleteFromDir(dir):
+def CompleteFromDir(directory):
'''
- This is necessary so that we get the imports from the same dir where the file
+ This is necessary so that we get the imports from the same directory where the file
we are completing is located.
'''
global currDirModule
if currDirModule is not None:
- del sys.path[currDirModule]
+ if len(sys.path) > 0 and sys.path[0] == currDirModule:
+ del sys.path[0]
- sys.path.insert(0, dir)
+ currDirModule = directory
+ sys.path.insert(0, directory)
def ChangePythonPath(pythonpath):
'''Changes the pythonpath (clears all the previous pythonpath)
-
+
@param pythonpath: string with paths separated by |
'''
-
+
split = pythonpath.split('|')
sys.path = []
for path in split:
path = path.strip()
if len(path) > 0:
sys.path.append(path)
-
-class KeepAliveThread(Thread):
- def __init__(self, socket):
- Thread.__init__(self)
- self.socket = socket
- self.processMsgFunc = None
- self.lastMsg = None
-
- def run(self):
- time.sleep(0.1)
-
- def send(s, msg):
- if IS_PYTHON3K:
- s.send(bytearray(msg, 'utf-8'))
- else:
- s.send(msg)
-
- while self.lastMsg == None:
-
- if self.processMsgFunc != None:
- s = MSG_PROCESSING_PROGRESS % quote_plus(self.processMsgFunc())
- sent = send(self.socket, s)
- else:
- sent = send(self.socket, MSG_PROCESSING)
- if sent == 0:
- sys.exit(0) #connection broken
- time.sleep(0.1)
- sent = send(self.socket, self.lastMsg)
- if sent == 0:
- sys.exit(0) #connection broken
-
+
class Processor:
def __init__(self):
- # nothing to do
- return
-
+ # nothing to do
+ return
+
def removeInvalidChars(self, msg):
try:
msg = str(msg)
except UnicodeDecodeError:
pass
-
+
if msg:
try:
return quote_plus(msg)
@@ -193,7 +163,7 @@ class Processor:
sys.stdout.write('error making quote plus in %s\n' % (msg,))
raise
return ' '
-
+
def formatCompletionMessage(self, defFile, completionsList):
'''
Format the completions suggestions in the following format:
@@ -203,41 +173,43 @@ class Processor:
compMsg.append('%s' % defFile)
for tup in completionsList:
compMsg.append(',')
-
+
compMsg.append('(')
- compMsg.append(str(self.removeInvalidChars(tup[0]))) #token
+ compMsg.append(str(self.removeInvalidChars(tup[0]))) # token
compMsg.append(',')
- compMsg.append(self.removeInvalidChars(tup[1])) #description
+ compMsg.append(self.removeInvalidChars(tup[1])) # description
if(len(tup) > 2):
compMsg.append(',')
- compMsg.append(self.removeInvalidChars(tup[2])) #args - only if function.
-
+ compMsg.append(self.removeInvalidChars(tup[2])) # args - only if function.
+
if(len(tup) > 3):
compMsg.append(',')
- compMsg.append(self.removeInvalidChars(tup[3])) #TYPE
-
+ compMsg.append(self.removeInvalidChars(tup[3])) # TYPE
+
compMsg.append(')')
-
+
return '%s(%s)%s' % (MSG_COMPLETIONS, ''.join(compMsg), MSG_END)
-
+
class T(Thread):
- def __init__(self, thisP, serverP):
+ def __init__(self, port):
Thread.__init__(self)
- self.thisPort = thisP
- self.serverPort = serverP
- self.socket = None #socket to send messages.
+ self.ended = False
+ self.port = port
+ self.socket = None # socket to send messages.
self.processor = Processor()
def connectToServer(self):
+ import socket
+
self.socket = s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
- s.connect((HOST, self.serverPort))
+ s.connect((HOST, self.port))
except:
- sys.stderr.write('Error on connectToServer with parameters: host: %s port: %s\n' % (HOST, self.serverPort))
+ sys.stderr.write('Error on connectToServer with parameters: host: %s port: %s\n' % (HOST, self.port))
raise
def getCompletionsMessage(self, defFile, completionsList):
@@ -245,7 +217,7 @@ class T(Thread):
get message with completions.
'''
return self.processor.formatCompletionMessage(defFile, completionsList)
-
+
def getTokenAndData(self, data):
'''
When we receive this, we have 'token):data'
@@ -256,129 +228,168 @@ class T(Thread):
token = token + c
else:
break;
-
+
return token, data.lstrip(token + '):')
-
+ def emulated_sendall(self, msg):
+ MSGLEN = 1024 * 20
+
+ totalsent = 0
+ while totalsent < MSGLEN:
+ sent = self.socket.send(msg[totalsent:])
+ if sent == 0:
+ return
+ totalsent = totalsent + sent
+
+
+ def send(self, msg):
+ if not hasattr(self.socket, 'sendall'):
+ #Older versions (jython 2.1)
+ self.emulated_sendall(msg)
+ else:
+ if IS_PYTHON3K:
+ self.socket.sendall(bytearray(msg, 'utf-8'))
+ else:
+ self.socket.sendall(msg)
+
+
def run(self):
# Echo server program
try:
import _pydev_log
log = _pydev_log.Log()
-
- dbg(SERVER_NAME + ' creating socket' , INFO1)
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.bind((HOST, self.thisPort))
- except:
- sys.stderr.write('Error connecting with parameters: host: %s port: %s\n' % (HOST, self.serverPort))
- raise
- s.listen(1) #socket to receive messages.
-
-
- #we stay here until we are connected.
- #we only accept 1 client.
- #the exit message for the server is @@KILL_SERVER_END@@
- dbg(SERVER_NAME + ' waiting for connection' , INFO1)
- conn, addr = s.accept()
- time.sleep(0.5) #wait a little before connecting to JAVA server
-
- dbg(SERVER_NAME + ' waiting to java client' , INFO1)
- #after being connected, create a socket as a client.
+
+ dbg(SERVER_NAME + ' connecting to java server on %s (%s)' % (HOST, self.port) , INFO1)
+ # after being connected, create a socket as a client.
self.connectToServer()
-
- dbg(SERVER_NAME + ' Connected by ' + str(addr), INFO1)
-
-
- while 1:
+
+ dbg(SERVER_NAME + ' Connected to java server', INFO1)
+
+
+ while not self.ended:
data = ''
- returnMsg = ''
- keepAliveThread = KeepAliveThread(self.socket)
-
+
while data.find(MSG_END) == -1:
- received = conn.recv(BUFFER_SIZE)
+ received = self.socket.recv(BUFFER_SIZE)
if len(received) == 0:
- sys.exit(0) #ok, connection ended
+ sys.exit(0) # ok, connection ended
if IS_PYTHON3K:
data = data + received.decode('utf-8')
else:
data = data + received
-
+
try:
try:
if data.find(MSG_KILL_SERVER) != -1:
dbg(SERVER_NAME + ' kill message received', INFO1)
- #break if we received kill message.
+ # break if we received kill message.
self.ended = True
sys.exit(0)
-
+
dbg(SERVER_NAME + ' starting keep alive thread', INFO2)
- keepAliveThread.start()
-
+
if data.find(MSG_PYTHONPATH) != -1:
comps = []
for p in _sys_path:
comps.append((p, ' '))
- returnMsg = self.getCompletionsMessage(None, comps)
-
+ self.send(self.getCompletionsMessage(None, comps))
+
else:
data = data[:data.rfind(MSG_END)]
-
+
if data.startswith(MSG_IMPORTS):
- data = data.replace(MSG_IMPORTS, '')
+ data = data[len(MSG_IMPORTS):]
data = unquote_plus(data)
- defFile, comps = importsTipper.GenerateTip(data, log)
- returnMsg = self.getCompletionsMessage(defFile, comps)
-
+ defFile, comps = _pydev_imports_tipper.GenerateTip(data, log)
+ self.send(self.getCompletionsMessage(defFile, comps))
+
elif data.startswith(MSG_CHANGE_PYTHONPATH):
- data = data.replace(MSG_CHANGE_PYTHONPATH, '')
+ data = data[len(MSG_CHANGE_PYTHONPATH):]
data = unquote_plus(data)
ChangePythonPath(data)
- returnMsg = MSG_OK
-
+ self.send(MSG_OK)
+
+ elif data.startswith(MSG_JEDI):
+ data = data[len(MSG_JEDI):]
+ data = unquote_plus(data)
+ line, column, encoding, path, source = data.split('|', 4)
+ try:
+ import jedi # @UnresolvedImport
+ except:
+ self.send(self.getCompletionsMessage(None, [('Error on import jedi', 'Error importing jedi', '')]))
+ else:
+ script = jedi.Script(
+ # Line +1 because it expects lines 1-based (and col 0-based)
+ source=source,
+ line=int(line) + 1,
+ column=int(column),
+ source_encoding=encoding,
+ path=path,
+ )
+ lst = []
+ for completion in script.completions():
+ t = completion.type
+ if t == 'class':
+ t = '1'
+
+ elif t == 'function':
+ t = '2'
+
+ elif t == 'import':
+ t = '0'
+
+ elif t == 'keyword':
+ continue # Keywords are already handled in PyDev
+
+ elif t == 'statement':
+ t = '3'
+
+ else:
+ t = '-1'
+
+ # gen list(tuple(name, doc, args, type))
+ lst.append((completion.name, '', '', t))
+ self.send(self.getCompletionsMessage('empty', lst))
+
elif data.startswith(MSG_SEARCH):
- data = data.replace(MSG_SEARCH, '')
+ data = data[len(MSG_SEARCH):]
data = unquote_plus(data)
- (f, line, col), foundAs = importsTipper.Search(data)
- returnMsg = self.getCompletionsMessage(f, [(line, col, foundAs)])
-
+ (f, line, col), foundAs = _pydev_imports_tipper.Search(data)
+ self.send(self.getCompletionsMessage(f, [(line, col, foundAs)]))
+
elif data.startswith(MSG_CHANGE_DIR):
- data = data.replace(MSG_CHANGE_DIR, '')
+ data = data[len(MSG_CHANGE_DIR):]
data = unquote_plus(data)
CompleteFromDir(data)
- returnMsg = MSG_OK
-
- elif data.startswith(MSG_BIKE):
- returnMsg = MSG_INVALID_REQUEST #No longer supported.
-
+ self.send(MSG_OK)
+
else:
- returnMsg = MSG_INVALID_REQUEST
+ self.send(MSG_INVALID_REQUEST)
except SystemExit:
- returnMsg = self.getCompletionsMessage(None, [('Exit:', 'SystemExit', '')])
- keepAliveThread.lastMsg = returnMsg
+ self.send(self.getCompletionsMessage(None, [('Exit:', 'SystemExit', '')]))
raise
+
except:
dbg(SERVER_NAME + ' exception occurred', ERROR)
s = StringIO.StringIO()
traceback.print_exc(file=s)
-
+
err = s.getvalue()
dbg(SERVER_NAME + ' received error: ' + str(err), ERROR)
- returnMsg = self.getCompletionsMessage(None, [('ERROR:', '%s\nLog:%s' % (err, log.GetContents()), '')])
-
-
+ self.send(self.getCompletionsMessage(None, [('ERROR:', '%s\nLog:%s' % (err, log.GetContents()), '')]))
+
+
finally:
log.Clear()
- keepAliveThread.lastMsg = returnMsg
-
- conn.close()
+
+ self.socket.close()
self.ended = True
- sys.exit(0) #connection broken
-
-
+ sys.exit(0) # connection broken
+
+
except SystemExit:
raise
- #No need to log SystemExit error
+ # No need to log SystemExit error
except:
s = StringIO.StringIO()
exc_info = sys.exc_info()
@@ -388,12 +399,13 @@ class T(Thread):
dbg(SERVER_NAME + ' received error: ' + str(err), ERROR)
raise
+
+
if __name__ == '__main__':
- thisPort = int(sys.argv[1]) #this is from where we want to receive messages.
- serverPort = int(sys.argv[2])#this is where we want to write messages.
-
- t = T(thisPort, serverPort)
+ port = int(sys.argv[1]) # this is from where we want to receive messages.
+
+ t = T(port)
dbg(SERVER_NAME + ' will start', INFO1)
t.start()
time.sleep(5)
diff --git a/python/helpers/pydev/pydev_app_engine_debug_startup.py b/python/helpers/pydev/pydev_app_engine_debug_startup.py
new file mode 100644
index 000000000000..464f0ddf3464
--- /dev/null
+++ b/python/helpers/pydev/pydev_app_engine_debug_startup.py
@@ -0,0 +1,21 @@
+if False:
+ config = None
+
+
+# See: https://docs.google.com/document/d/1CCSaRiIWCLgbD3OwmuKsRoHHDfBffbROWyVWWL0ZXN4/edit
+if ':' not in config.version_id:
+ # The default server version_id does not contain ':'
+ import json
+ import os
+ import sys
+
+ startup = config.python_config.startup_args
+ if not startup:
+ raise AssertionError('Expected --python_startup_args to be passed from the pydev debugger.')
+
+ setup = json.loads(startup)
+ pydevd_path = setup['pydevd']
+ sys.path.append(os.path.dirname(pydevd_path))
+
+ import pydevd
+ pydevd.settrace(setup['client'], port=setup['port'], suspend=False, trace_only_current_thread=False)
diff --git a/python/helpers/pydev/pydev_console_utils.py b/python/helpers/pydev/pydev_console_utils.py
index 54a85850c48f..571ae871b3ab 100644
--- a/python/helpers/pydev/pydev_console_utils.py
+++ b/python/helpers/pydev/pydev_console_utils.py
@@ -215,7 +215,16 @@ class BaseInterpreterInterface:
try:
self.startExec()
+ if hasattr(self, 'debugger'):
+ import pydevd_tracing
+ pydevd_tracing.SetTrace(self.debugger.trace_dispatch)
+
more = self.doAddExec(code_fragment)
+
+ if hasattr(self, 'debugger'):
+ import pydevd_tracing
+ pydevd_tracing.SetTrace(None)
+
self.finishExec(more)
finally:
if help is not None:
@@ -283,9 +292,9 @@ class BaseInterpreterInterface:
if doc is not None:
return doc
- import jyimportsTipper
+ import _pydev_jy_imports_tipper
- is_method, infos = jyimportsTipper.ismethod(obj)
+ is_method, infos = _pydev_jy_imports_tipper.ismethod(obj)
ret = ''
if is_method:
for info in infos:
@@ -400,4 +409,92 @@ class BaseInterpreterInterface:
return xml
def changeVariable(self, attr, value):
- Exec('%s=%s' % (attr, value), self.getNamespace(), self.getNamespace()) \ No newline at end of file
+ Exec('%s=%s' % (attr, value), self.getNamespace(), self.getNamespace())
+
+ def _findFrame(self, thread_id, frame_id):
+ '''
+ Used to show console with variables connection.
+ Always return a frame where the locals map to our internal namespace.
+ '''
+ VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java
+ VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java
+ if thread_id == VIRTUAL_CONSOLE_ID and frame_id == VIRTUAL_FRAME_ID:
+ f = FakeFrame()
+ f.f_globals = {} #As globals=locals here, let's simply let it empty (and save a bit of network traffic).
+ f.f_locals = self.getNamespace()
+ return f
+ else:
+ return self.orig_findFrame(thread_id, frame_id)
+
+ def connectToDebugger(self, debuggerPort):
+ '''
+ Used to show console with variables connection.
+ Mainly, monkey-patches things in the debugger structure so that the debugger protocol works.
+ '''
+ try:
+ # Try to import the packages needed to attach the debugger
+ import pydevd
+ import pydevd_vars
+ import threading
+ except:
+ # This happens on Jython embedded in host eclipse
+ import traceback;traceback.print_exc()
+ return ('pydevd is not available, cannot connect',)
+
+ import pydev_localhost
+ threading.currentThread().__pydevd_id__ = "console_main"
+
+ self.orig_findFrame = pydevd_vars.findFrame
+ pydevd_vars.findFrame = self._findFrame
+
+ self.debugger = pydevd.PyDB()
+ try:
+ self.debugger.connect(pydev_localhost.get_localhost(), debuggerPort)
+ self.debugger.prepareToRun()
+ import pydevd_tracing
+ pydevd_tracing.SetTrace(None)
+ except:
+ import traceback;traceback.print_exc()
+ return ('Failed to connect to target debugger.')
+
+ # Register to process commands when idle
+ self.debugrunning = False
+ try:
+ self.server.setDebugHook(self.debugger.processInternalCommands)
+ except:
+ import traceback;traceback.print_exc()
+ return ('Version of Python does not support debuggable Interactive Console.')
+
+ return ('connect complete',)
+
+ def hello(self, input_str):
+ # Don't care what the input string is
+ return ("Hello eclipse",)
+
+ def enableGui(self, guiname):
+ ''' Enable the GUI specified in guiname (see inputhook for list).
+ As with IPython, enabling multiple GUIs isn't an error, but
+ only the last one's main loop runs and it may not work
+ '''
+ from pydev_versioncheck import versionok_for_gui
+ if versionok_for_gui():
+ try:
+ from pydev_ipython.inputhook import enable_gui
+ enable_gui(guiname)
+ except:
+ sys.stderr.write("Failed to enable GUI event loop integration for '%s'\n" % guiname)
+ import traceback;traceback.print_exc()
+ elif guiname not in ['none', '', None]:
+ # Only print a warning if the guiname was going to do something
+ sys.stderr.write("PyDev console: Python version does not support GUI event loop integration for '%s'\n" % guiname)
+ # Return value does not matter, so return back what was sent
+ return guiname
+
+#=======================================================================================================================
+# FakeFrame
+#=======================================================================================================================
+class FakeFrame:
+ '''
+ Used to show console with variables connection.
+ A class to be used as a mock of a frame.
+ ''' \ No newline at end of file
diff --git a/python/helpers/pydev/pydev_imports.py b/python/helpers/pydev/pydev_imports.py
index 9dce8c4ec9e4..06858750c97d 100644
--- a/python/helpers/pydev/pydev_imports.py
+++ b/python/helpers/pydev/pydev_imports.py
@@ -33,4 +33,61 @@ try:
else:
import Queue as _queue
except:
- import queue as _queue
+ import queue as _queue #@UnresolvedImport
+
+try:
+ from pydevd_exec import Exec
+except:
+ from pydevd_exec2 import Exec
+
+try:
+ from urllib import quote
+except:
+ from urllib.parse import quote #@UnresolvedImport
+
+
+import os
+try:
+ relpath = os.path.relpath
+except:
+ # Only there from 2.6 onwards... let's provide a replacement.
+ def _split_path(path):
+ parts = []
+ loc = path
+
+ while loc != os.curdir and loc != os.pardir:
+ prev = loc
+ loc, child = os.path.split(prev)
+ if loc == prev:
+ break
+
+ parts.append(child)
+
+ parts.append(loc)
+ parts.reverse()
+ return parts
+
+ def relpath(path, start=None):
+ if start is None:
+ start = os.curdir
+ origin = os.path.abspath(path)
+ start = os.path.abspath(start)
+
+ orig_list = _split_path(os.path.normcase(origin))
+ dest_list = _split_path(start)
+
+ if orig_list[0] != os.path.normcase(dest_list[0]):
+ return start
+
+ i = 0
+ for start_seg, dest_seg in zip(orig_list, dest_list):
+ if start_seg != os.path.normcase(dest_seg):
+ break
+ i += 1
+
+ segments = [os.pardir] * (len(orig_list) - i)
+ segments += dest_list[i:]
+ if len(segments) == 0:
+ return os.curdir
+ else:
+ return os.path.join(*segments)
diff --git a/python/helpers/pydev/pydev_ipython/README b/python/helpers/pydev/pydev_ipython/README
new file mode 100644
index 000000000000..185d417d80dc
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/README
@@ -0,0 +1,8 @@
+# Parts of IPython, files from: https://github.com/ipython/ipython/tree/rel-1.0.0/IPython
+# The files in this package are extracted from IPython to aid the main loop integration
+# See tests_mainloop for some manually runable tests
+
+# What we are doing is reusing the "inputhook" functionality (i.e. what in IPython
+# ends up on PyOS_InputHook) and using it in the pydevconsole context.
+# Rather that having the callbacks called in PyOS_InputHook, we use a custom XML-RPC
+# Server (HookableXMLRPCServer) that calls the inputhook when idle
diff --git a/python/helpers/pydev/pydev_ipython/__init__.py b/python/helpers/pydev/pydev_ipython/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/__init__.py
diff --git a/python/helpers/pydev/pydev_ipython/inputhook.py b/python/helpers/pydev/pydev_ipython/inputhook.py
new file mode 100644
index 000000000000..c016b25c9edd
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhook.py
@@ -0,0 +1,525 @@
+# coding: utf-8
+"""
+Inputhook management for GUI event loop integration.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import sys
+import select
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+# Constants for identifying the GUI toolkits.
+GUI_WX = 'wx'
+GUI_QT = 'qt'
+GUI_QT4 = 'qt4'
+GUI_GTK = 'gtk'
+GUI_TK = 'tk'
+GUI_OSX = 'osx'
+GUI_GLUT = 'glut'
+GUI_PYGLET = 'pyglet'
+GUI_GTK3 = 'gtk3'
+GUI_NONE = 'none' # i.e. disable
+
+#-----------------------------------------------------------------------------
+# Utilities
+#-----------------------------------------------------------------------------
+
+def ignore_CTRL_C():
+ """Ignore CTRL+C (not implemented)."""
+ pass
+
+def allow_CTRL_C():
+ """Take CTRL+C into account (not implemented)."""
+ pass
+
+#-----------------------------------------------------------------------------
+# Main InputHookManager class
+#-----------------------------------------------------------------------------
+
+
+class InputHookManager(object):
+ """Manage PyOS_InputHook for different GUI toolkits.
+
+ This class installs various hooks under ``PyOSInputHook`` to handle
+ GUI event loop integration.
+ """
+
+ def __init__(self):
+ self._return_control_callback = None
+ self._apps = {}
+ self._reset()
+
+ def _reset(self):
+ self._callback_pyfunctype = None
+ self._callback = None
+ self._current_gui = None
+
+ def set_return_control_callback(self, return_control_callback):
+ self._return_control_callback = return_control_callback
+
+ def get_return_control_callback(self):
+ return self._return_control_callback
+
+ def return_control(self):
+ return self._return_control_callback()
+
+ def get_inputhook(self):
+ return self._callback
+
+ def set_inputhook(self, callback):
+ """Set inputhook to callback."""
+ # We don't (in the context of PyDev console) actually set PyOS_InputHook, but rather
+ # while waiting for input on xmlrpc we run this code
+ self._callback = callback
+
+ def clear_inputhook(self, app=None):
+ """Clear input hook.
+
+ Parameters
+ ----------
+ app : optional, ignored
+ This parameter is allowed only so that clear_inputhook() can be
+ called with a similar interface as all the ``enable_*`` methods. But
+ the actual value of the parameter is ignored. This uniform interface
+ makes it easier to have user-level entry points in the main IPython
+ app like :meth:`enable_gui`."""
+ self._reset()
+
+ def clear_app_refs(self, gui=None):
+ """Clear IPython's internal reference to an application instance.
+
+ Whenever we create an app for a user on qt4 or wx, we hold a
+ reference to the app. This is needed because in some cases bad things
+ can happen if a user doesn't hold a reference themselves. This
+ method is provided to clear the references we are holding.
+
+ Parameters
+ ----------
+ gui : None or str
+ If None, clear all app references. If ('wx', 'qt4') clear
+ the app for that toolkit. References are not held for gtk or tk
+ as those toolkits don't have the notion of an app.
+ """
+ if gui is None:
+ self._apps = {}
+ elif gui in self._apps:
+ del self._apps[gui]
+
+ def enable_wx(self, app=None):
+ """Enable event loop integration with wxPython.
+
+ Parameters
+ ----------
+ app : WX Application, optional.
+ Running application to use. If not given, we probe WX for an
+ existing application object, and create a new one if none is found.
+
+ Notes
+ -----
+ This methods sets the ``PyOS_InputHook`` for wxPython, which allows
+ the wxPython to integrate with terminal based applications like
+ IPython.
+
+ If ``app`` is not given we probe for an existing one, and return it if
+ found. If no existing app is found, we create an :class:`wx.App` as
+ follows::
+
+ import wx
+ app = wx.App(redirect=False, clearSigInt=False)
+ """
+ import wx
+ from distutils.version import LooseVersion as V
+ wx_version = V(wx.__version__).version
+
+ if wx_version < [2, 8]:
+ raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
+
+ from pydev_ipython.inputhookwx import inputhook_wx
+ self.set_inputhook(inputhook_wx)
+ self._current_gui = GUI_WX
+
+ if app is None:
+ app = wx.GetApp()
+ if app is None:
+ app = wx.App(redirect=False, clearSigInt=False)
+ app._in_event_loop = True
+ self._apps[GUI_WX] = app
+ return app
+
+ def disable_wx(self):
+ """Disable event loop integration with wxPython.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ if GUI_WX in self._apps:
+ self._apps[GUI_WX]._in_event_loop = False
+ self.clear_inputhook()
+
+ def enable_qt4(self, app=None):
+ """Enable event loop integration with PyQt4.
+
+ Parameters
+ ----------
+ app : Qt Application, optional.
+ Running application to use. If not given, we probe Qt for an
+ existing application object, and create a new one if none is found.
+
+ Notes
+ -----
+ This methods sets the PyOS_InputHook for PyQt4, which allows
+ the PyQt4 to integrate with terminal based applications like
+ IPython.
+
+ If ``app`` is not given we probe for an existing one, and return it if
+ found. If no existing app is found, we create an :class:`QApplication`
+ as follows::
+
+ from PyQt4 import QtCore
+ app = QtGui.QApplication(sys.argv)
+ """
+ from pydev_ipython.inputhookqt4 import create_inputhook_qt4
+ app, inputhook_qt4 = create_inputhook_qt4(self, app)
+ self.set_inputhook(inputhook_qt4)
+
+ self._current_gui = GUI_QT4
+ app._in_event_loop = True
+ self._apps[GUI_QT4] = app
+ return app
+
+ def disable_qt4(self):
+ """Disable event loop integration with PyQt4.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ if GUI_QT4 in self._apps:
+ self._apps[GUI_QT4]._in_event_loop = False
+ self.clear_inputhook()
+
+ def enable_gtk(self, app=None):
+ """Enable event loop integration with PyGTK.
+
+ Parameters
+ ----------
+ app : ignored
+ Ignored, it's only a placeholder to keep the call signature of all
+ gui activation methods consistent, which simplifies the logic of
+ supporting magics.
+
+ Notes
+ -----
+ This methods sets the PyOS_InputHook for PyGTK, which allows
+ the PyGTK to integrate with terminal based applications like
+ IPython.
+ """
+ from pydev_ipython.inputhookgtk import create_inputhook_gtk
+ self.set_inputhook(create_inputhook_gtk(self._stdin_file))
+ self._current_gui = GUI_GTK
+
+ def disable_gtk(self):
+ """Disable event loop integration with PyGTK.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ self.clear_inputhook()
+
+ def enable_tk(self, app=None):
+ """Enable event loop integration with Tk.
+
+ Parameters
+ ----------
+ app : toplevel :class:`Tkinter.Tk` widget, optional.
+ Running toplevel widget to use. If not given, we probe Tk for an
+ existing one, and create a new one if none is found.
+
+ Notes
+ -----
+ If you have already created a :class:`Tkinter.Tk` object, the only
+ thing done by this method is to register with the
+ :class:`InputHookManager`, since creating that object automatically
+ sets ``PyOS_InputHook``.
+ """
+ self._current_gui = GUI_TK
+ if app is None:
+ try:
+ import Tkinter as _TK
+ except:
+ # Python 3
+ import tkinter as _TK
+ app = _TK.Tk()
+ app.withdraw()
+ self._apps[GUI_TK] = app
+
+ from pydev_ipython.inputhooktk import create_inputhook_tk
+ self.set_inputhook(create_inputhook_tk(app))
+ return app
+
+ def disable_tk(self):
+ """Disable event loop integration with Tkinter.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ self.clear_inputhook()
+
+
+ def enable_glut(self, app=None):
+ """ Enable event loop integration with GLUT.
+
+ Parameters
+ ----------
+
+ app : ignored
+ Ignored, it's only a placeholder to keep the call signature of all
+ gui activation methods consistent, which simplifies the logic of
+ supporting magics.
+
+ Notes
+ -----
+
+ This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
+ integrate with terminal based applications like IPython. Due to GLUT
+ limitations, it is currently not possible to start the event loop
+ without first creating a window. You should thus not create another
+ window but use instead the created one. See 'gui-glut.py' in the
+ docs/examples/lib directory.
+
+ The default screen mode is set to:
+ glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
+ """
+
+ import OpenGL.GLUT as glut
+ from pydev_ipython.inputhookglut import glut_display_mode, \
+ glut_close, glut_display, \
+ glut_idle, inputhook_glut
+
+ if GUI_GLUT not in self._apps:
+ glut.glutInit(sys.argv)
+ glut.glutInitDisplayMode(glut_display_mode)
+ # This is specific to freeglut
+ if bool(glut.glutSetOption):
+ glut.glutSetOption(glut.GLUT_ACTION_ON_WINDOW_CLOSE,
+ glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS)
+ glut.glutCreateWindow(sys.argv[0])
+ glut.glutReshapeWindow(1, 1)
+ glut.glutHideWindow()
+ glut.glutWMCloseFunc(glut_close)
+ glut.glutDisplayFunc(glut_display)
+ glut.glutIdleFunc(glut_idle)
+ else:
+ glut.glutWMCloseFunc(glut_close)
+ glut.glutDisplayFunc(glut_display)
+ glut.glutIdleFunc(glut_idle)
+ self.set_inputhook(inputhook_glut)
+ self._current_gui = GUI_GLUT
+ self._apps[GUI_GLUT] = True
+
+
+ def disable_glut(self):
+ """Disable event loop integration with glut.
+
+ This sets PyOS_InputHook to NULL and set the display function to a
+ dummy one and set the timer to a dummy timer that will be triggered
+ very far in the future.
+ """
+ import OpenGL.GLUT as glut
+ from glut_support import glutMainLoopEvent # @UnresolvedImport
+
+ glut.glutHideWindow() # This is an event to be processed below
+ glutMainLoopEvent()
+ self.clear_inputhook()
+
+ def enable_pyglet(self, app=None):
+ """Enable event loop integration with pyglet.
+
+ Parameters
+ ----------
+ app : ignored
+ Ignored, it's only a placeholder to keep the call signature of all
+ gui activation methods consistent, which simplifies the logic of
+ supporting magics.
+
+ Notes
+ -----
+ This methods sets the ``PyOS_InputHook`` for pyglet, which allows
+ pyglet to integrate with terminal based applications like
+ IPython.
+
+ """
+ from pydev_ipython.inputhookpyglet import inputhook_pyglet
+ self.set_inputhook(inputhook_pyglet)
+ self._current_gui = GUI_PYGLET
+ return app
+
+ def disable_pyglet(self):
+ """Disable event loop integration with pyglet.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ self.clear_inputhook()
+
+ def enable_gtk3(self, app=None):
+ """Enable event loop integration with Gtk3 (gir bindings).
+
+ Parameters
+ ----------
+ app : ignored
+ Ignored, it's only a placeholder to keep the call signature of all
+ gui activation methods consistent, which simplifies the logic of
+ supporting magics.
+
+ Notes
+ -----
+ This methods sets the PyOS_InputHook for Gtk3, which allows
+ the Gtk3 to integrate with terminal based applications like
+ IPython.
+ """
+ from pydev_ipython.inputhookgtk3 import create_inputhook_gtk3
+ self.set_inputhook(create_inputhook_gtk3(self._stdin_file))
+ self._current_gui = GUI_GTK
+
+ def disable_gtk3(self):
+ """Disable event loop integration with PyGTK.
+
+ This merely sets PyOS_InputHook to NULL.
+ """
+ self.clear_inputhook()
+
+ def current_gui(self):
+ """Return a string indicating the currently active GUI or None."""
+ return self._current_gui
+
+inputhook_manager = InputHookManager()
+
+enable_wx = inputhook_manager.enable_wx
+disable_wx = inputhook_manager.disable_wx
+enable_qt4 = inputhook_manager.enable_qt4
+disable_qt4 = inputhook_manager.disable_qt4
+enable_gtk = inputhook_manager.enable_gtk
+disable_gtk = inputhook_manager.disable_gtk
+enable_tk = inputhook_manager.enable_tk
+disable_tk = inputhook_manager.disable_tk
+enable_glut = inputhook_manager.enable_glut
+disable_glut = inputhook_manager.disable_glut
+enable_pyglet = inputhook_manager.enable_pyglet
+disable_pyglet = inputhook_manager.disable_pyglet
+enable_gtk3 = inputhook_manager.enable_gtk3
+disable_gtk3 = inputhook_manager.disable_gtk3
+clear_inputhook = inputhook_manager.clear_inputhook
+set_inputhook = inputhook_manager.set_inputhook
+current_gui = inputhook_manager.current_gui
+clear_app_refs = inputhook_manager.clear_app_refs
+
+# We maintain this as stdin_ready so that the individual inputhooks
+# can diverge as little as possible from their IPython sources
+stdin_ready = inputhook_manager.return_control
+set_return_control_callback = inputhook_manager.set_return_control_callback
+get_return_control_callback = inputhook_manager.get_return_control_callback
+get_inputhook = inputhook_manager.get_inputhook
+
+# Convenience function to switch amongst them
+def enable_gui(gui=None, app=None):
+ """Switch amongst GUI input hooks by name.
+
+ This is just a utility wrapper around the methods of the InputHookManager
+ object.
+
+ Parameters
+ ----------
+ gui : optional, string or None
+ If None (or 'none'), clears input hook, otherwise it must be one
+ of the recognized GUI names (see ``GUI_*`` constants in module).
+
+ app : optional, existing application object.
+ For toolkits that have the concept of a global app, you can supply an
+ existing one. If not given, the toolkit will be probed for one, and if
+ none is found, a new one will be created. Note that GTK does not have
+ this concept, and passing an app if ``gui=="GTK"`` will raise an error.
+
+ Returns
+ -------
+ The output of the underlying gui switch routine, typically the actual
+ PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
+ one.
+ """
+
+ if get_return_control_callback() is None:
+ raise ValueError("A return_control_callback must be supplied as a reference before a gui can be enabled")
+
+ guis = {GUI_NONE: clear_inputhook,
+ GUI_OSX: lambda app = False: None,
+ GUI_TK: enable_tk,
+ GUI_GTK: enable_gtk,
+ GUI_WX: enable_wx,
+ GUI_QT: enable_qt4, # qt3 not supported
+ GUI_QT4: enable_qt4,
+ GUI_GLUT: enable_glut,
+ GUI_PYGLET: enable_pyglet,
+ GUI_GTK3: enable_gtk3,
+ }
+ try:
+ gui_hook = guis[gui]
+ except KeyError:
+ if gui is None or gui == '':
+ gui_hook = clear_inputhook
+ else:
+ e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
+ raise ValueError(e)
+ return gui_hook(app)
+
+__all__ = [
+ "GUI_WX",
+ "GUI_QT",
+ "GUI_QT4",
+ "GUI_GTK",
+ "GUI_TK",
+ "GUI_OSX",
+ "GUI_GLUT",
+ "GUI_PYGLET",
+ "GUI_GTK3",
+ "GUI_NONE",
+
+
+ "ignore_CTRL_C",
+ "allow_CTRL_C",
+
+ "InputHookManager",
+
+ "inputhook_manager",
+
+ "enable_wx",
+ "disable_wx",
+ "enable_qt4",
+ "disable_qt4",
+ "enable_gtk",
+ "disable_gtk",
+ "enable_tk",
+ "disable_tk",
+ "enable_glut",
+ "disable_glut",
+ "enable_pyglet",
+ "disable_pyglet",
+ "enable_gtk3",
+ "disable_gtk3",
+ "clear_inputhook",
+ "set_inputhook",
+ "current_gui",
+ "clear_app_refs",
+
+ "stdin_ready",
+ "set_return_control_callback",
+ "get_return_control_callback",
+ "get_inputhook",
+
+ "enable_gui"]
diff --git a/python/helpers/pydev/pydev_ipython/inputhookglut.py b/python/helpers/pydev/pydev_ipython/inputhookglut.py
new file mode 100644
index 000000000000..f0683ba5890e
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookglut.py
@@ -0,0 +1,153 @@
+# coding: utf-8
+"""
+GLUT Inputhook support functions
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+# GLUT is quite an old library and it is difficult to ensure proper
+# integration within IPython since original GLUT does not allow to handle
+# events one by one. Instead, it requires for the mainloop to be entered
+# and never returned (there is not even a function to exit he
+# mainloop). Fortunately, there are alternatives such as freeglut
+# (available for linux and windows) and the OSX implementation gives
+# access to a glutCheckLoop() function that blocks itself until a new
+# event is received. This means we have to setup the idle callback to
+# ensure we got at least one event that will unblock the function.
+#
+# Furthermore, it is not possible to install these handlers without a window
+# being first created. We choose to make this window invisible. This means that
+# display mode options are set at this level and user won't be able to change
+# them later without modifying the code. This should probably be made available
+# via IPython options system.
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+import os
+import sys
+import time
+import signal
+import OpenGL.GLUT as glut
+import OpenGL.platform as platform
+from timeit import default_timer as clock
+from pydev_ipython.inputhook import stdin_ready
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+# Frame per second : 60
+# Should probably be an IPython option
+glut_fps = 60
+
+
+# Display mode : double buffeed + rgba + depth
+# Should probably be an IPython option
+glut_display_mode = (glut.GLUT_DOUBLE |
+ glut.GLUT_RGBA |
+ glut.GLUT_DEPTH)
+
+glutMainLoopEvent = None
+if sys.platform == 'darwin':
+ try:
+ glutCheckLoop = platform.createBaseFunction(
+ 'glutCheckLoop', dll=platform.GLUT, resultType=None,
+ argTypes=[],
+ doc='glutCheckLoop( ) -> None',
+ argNames=(),
+ )
+ except AttributeError:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions'''
+ '''Consider installing freeglut.''')
+ glutMainLoopEvent = glutCheckLoop
+elif glut.HAVE_FREEGLUT:
+ glutMainLoopEvent = glut.glutMainLoopEvent
+else:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions. '''
+ '''Consider installing freeglut.''')
+
+
+#-----------------------------------------------------------------------------
+# Callback functions
+#-----------------------------------------------------------------------------
+
+def glut_display():
+ # Dummy display function
+ pass
+
+def glut_idle():
+ # Dummy idle function
+ pass
+
+def glut_close():
+ # Close function only hides the current window
+ glut.glutHideWindow()
+ glutMainLoopEvent()
+
+def glut_int_handler(signum, frame):
+ # Catch sigint and print the defautl message
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+ print '\nKeyboardInterrupt'
+ # Need to reprint the prompt at this stage
+
+
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+def inputhook_glut():
+ """Run the pyglet event loop by processing pending events only.
+
+ This keeps processing pending events until stdin is ready. After
+ processing all pending events, a call to time.sleep is inserted. This is
+ needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
+ though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+
+ signal.signal(signal.SIGINT, glut_int_handler)
+
+ try:
+ t = clock()
+
+ # Make sure the default window is set after a window has been closed
+ if glut.glutGetWindow() == 0:
+ glut.glutSetWindow( 1 )
+ glutMainLoopEvent()
+ return 0
+
+ while not stdin_ready():
+ glutMainLoopEvent()
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ except KeyboardInterrupt:
+ pass
+ return 0
diff --git a/python/helpers/pydev/pydev_ipython/inputhookgtk.py b/python/helpers/pydev/pydev_ipython/inputhookgtk.py
new file mode 100644
index 000000000000..8c021d3c9536
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookgtk.py
@@ -0,0 +1,36 @@
+# encoding: utf-8
+"""
+Enable pygtk to be used interacive by setting PyOS_InputHook.
+
+Authors: Brian Granger
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import gtk, gobject
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+
+def _main_quit(*args, **kwargs):
+ gtk.main_quit()
+ return False
+
+def create_inputhook_gtk(stdin_file):
+ def inputhook_gtk():
+ gobject.io_add_watch(stdin_file, gobject.IO_IN, _main_quit)
+ gtk.main()
+ return 0
+ return inputhook_gtk
+
diff --git a/python/helpers/pydev/pydev_ipython/inputhookgtk3.py b/python/helpers/pydev/pydev_ipython/inputhookgtk3.py
new file mode 100644
index 000000000000..f2ca39f39003
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookgtk3.py
@@ -0,0 +1,35 @@
+# encoding: utf-8
+"""
+Enable Gtk3 to be used interacive by IPython.
+
+Authors: Thomi Richards
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2012, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from gi.repository import Gtk, GLib # @UnresolvedImport
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+def _main_quit(*args, **kwargs):
+ Gtk.main_quit()
+ return False
+
+
+def create_inputhook_gtk3(stdin_file):
+ def inputhook_gtk3():
+ GLib.io_add_watch(stdin_file, GLib.IO_IN, _main_quit)
+ Gtk.main()
+ return 0
+ return inputhook_gtk3
diff --git a/python/helpers/pydev/pydev_ipython/inputhookpyglet.py b/python/helpers/pydev/pydev_ipython/inputhookpyglet.py
new file mode 100644
index 000000000000..0cbb87f34b6d
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookpyglet.py
@@ -0,0 +1,92 @@
+# encoding: utf-8
+"""
+Enable pyglet to be used interacive by setting PyOS_InputHook.
+
+Authors
+-------
+
+* Nicolas P. Rougier
+* Fernando Perez
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+import time
+from timeit import default_timer as clock
+import pyglet
+from pydev_ipython.inputhook import stdin_ready
+
+
+# On linux only, window.flip() has a bug that causes an AttributeError on
+# window close. For details, see:
+# http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
+
+if sys.platform.startswith('linux'):
+ def flip(window):
+ try:
+ window.flip()
+ except AttributeError:
+ pass
+else:
+ def flip(window):
+ window.flip()
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+def inputhook_pyglet():
+ """Run the pyglet event loop by processing pending events only.
+
+ This keeps processing pending events until stdin is ready. After
+ processing all pending events, a call to time.sleep is inserted. This is
+ needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
+ though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ t = clock()
+ while not stdin_ready():
+ pyglet.clock.tick()
+ for window in pyglet.app.windows:
+ window.switch_to()
+ window.dispatch_events()
+ window.dispatch_event('on_draw')
+ flip(window)
+
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ except KeyboardInterrupt:
+ pass
+ return 0
diff --git a/python/helpers/pydev/pydev_ipython/inputhookqt4.py b/python/helpers/pydev/pydev_ipython/inputhookqt4.py
new file mode 100644
index 000000000000..f4f32a344e8a
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookqt4.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+"""
+Qt4's inputhook support function
+
+Author: Christian Boos
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import signal
+import threading
+
+from pydev_ipython.qt_for_kernel import QtCore, QtGui
+from pydev_ipython.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready
+
+# To minimise future merging complexity, rather than edit the entire code base below
+# we fake InteractiveShell here
+class InteractiveShell:
+ _instance = None
+ @classmethod
+ def instance(cls):
+ if cls._instance is None:
+ cls._instance = cls()
+ return cls._instance
+ def set_hook(self, *args, **kwargs):
+ # We don't consider the pre_prompt_hook because we don't have
+ # KeyboardInterrupts to consider since we are running under PyDev
+ pass
+
+
+#-----------------------------------------------------------------------------
+# Module Globals
+#-----------------------------------------------------------------------------
+
+got_kbdint = False
+sigint_timer = None
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+def create_inputhook_qt4(mgr, app=None):
+ """Create an input hook for running the Qt4 application event loop.
+
+ Parameters
+ ----------
+ mgr : an InputHookManager
+
+ app : Qt Application, optional.
+ Running application to use. If not given, we probe Qt for an
+ existing application object, and create a new one if none is found.
+
+ Returns
+ -------
+ A pair consisting of a Qt Application (either the one given or the
+ one found or created) and a inputhook.
+
+ Notes
+ -----
+ We use a custom input hook instead of PyQt4's default one, as it
+ interacts better with the readline packages (issue #481).
+
+ The inputhook function works in tandem with a 'pre_prompt_hook'
+ which automatically restores the hook as an inputhook in case the
+ latter has been temporarily disabled after having intercepted a
+ KeyboardInterrupt.
+ """
+
+ if app is None:
+ app = QtCore.QCoreApplication.instance()
+ if app is None:
+ app = QtGui.QApplication([" "])
+
+ # Re-use previously created inputhook if any
+ ip = InteractiveShell.instance()
+ if hasattr(ip, '_inputhook_qt4'):
+ return app, ip._inputhook_qt4
+
+ # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of
+ # hooks (they both share the got_kbdint flag)
+
+ def inputhook_qt4():
+ """PyOS_InputHook python hook for Qt4.
+
+ Process pending Qt events and if there's no pending keyboard
+ input, spend a short slice of time (50ms) running the Qt event
+ loop.
+
+ As a Python ctypes callback can't raise an exception, we catch
+ the KeyboardInterrupt and temporarily deactivate the hook,
+ which will let a *second* CTRL+C be processed normally and go
+ back to a clean prompt line.
+ """
+ try:
+ allow_CTRL_C()
+ app = QtCore.QCoreApplication.instance()
+ if not app: # shouldn't happen, but safer if it happens anyway...
+ return 0
+ app.processEvents(QtCore.QEventLoop.AllEvents, 300)
+ if not stdin_ready():
+ # Generally a program would run QCoreApplication::exec()
+ # from main() to enter and process the Qt event loop until
+ # quit() or exit() is called and the program terminates.
+ #
+ # For our input hook integration, we need to repeatedly
+ # enter and process the Qt event loop for only a short
+ # amount of time (say 50ms) to ensure that Python stays
+ # responsive to other user inputs.
+ #
+ # A naive approach would be to repeatedly call
+ # QCoreApplication::exec(), using a timer to quit after a
+ # short amount of time. Unfortunately, QCoreApplication
+ # emits an aboutToQuit signal before stopping, which has
+ # the undesirable effect of closing all modal windows.
+ #
+ # To work around this problem, we instead create a
+ # QEventLoop and call QEventLoop::exec(). Other than
+ # setting some state variables which do not seem to be
+ # used anywhere, the only thing QCoreApplication adds is
+ # the aboutToQuit signal which is precisely what we are
+ # trying to avoid.
+ timer = QtCore.QTimer()
+ event_loop = QtCore.QEventLoop()
+ timer.timeout.connect(event_loop.quit)
+ while not stdin_ready():
+ timer.start(50)
+ event_loop.exec_()
+ timer.stop()
+ except KeyboardInterrupt:
+ global got_kbdint, sigint_timer
+
+ ignore_CTRL_C()
+ got_kbdint = True
+ mgr.clear_inputhook()
+
+ # This generates a second SIGINT so the user doesn't have to
+ # press CTRL+C twice to get a clean prompt.
+ #
+ # Since we can't catch the resulting KeyboardInterrupt here
+ # (because this is a ctypes callback), we use a timer to
+ # generate the SIGINT after we leave this callback.
+ #
+ # Unfortunately this doesn't work on Windows (SIGINT kills
+ # Python and CTRL_C_EVENT doesn't work).
+ if(os.name == 'posix'):
+ pid = os.getpid()
+ if(not sigint_timer):
+ sigint_timer = threading.Timer(.01, os.kill,
+ args=[pid, signal.SIGINT] )
+ sigint_timer.start()
+ else:
+ print("\nKeyboardInterrupt - Ctrl-C again for new prompt")
+
+
+ except: # NO exceptions are allowed to escape from a ctypes callback
+ ignore_CTRL_C()
+ from traceback import print_exc
+ print_exc()
+ print("Got exception from inputhook_qt4, unregistering.")
+ mgr.clear_inputhook()
+ finally:
+ allow_CTRL_C()
+ return 0
+
+ def preprompthook_qt4(ishell):
+ """'pre_prompt_hook' used to restore the Qt4 input hook
+
+ (in case the latter was temporarily deactivated after a
+ CTRL+C)
+ """
+ global got_kbdint, sigint_timer
+
+ if(sigint_timer):
+ sigint_timer.cancel()
+ sigint_timer = None
+
+ if got_kbdint:
+ mgr.set_inputhook(inputhook_qt4)
+ got_kbdint = False
+
+ ip._inputhook_qt4 = inputhook_qt4
+ ip.set_hook('pre_prompt_hook', preprompthook_qt4)
+
+ return app, inputhook_qt4
diff --git a/python/helpers/pydev/pydev_ipython/inputhooktk.py b/python/helpers/pydev/pydev_ipython/inputhooktk.py
new file mode 100644
index 000000000000..e245cc05c2e1
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhooktk.py
@@ -0,0 +1,23 @@
+# encoding: utf-8
+# Unlike what IPython does, we need to have an explicit inputhook because tkinter handles
+# input hook in the C Source code
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from pydev_ipython.inputhook import stdin_ready
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+TCL_DONT_WAIT = 1 << 1
+
+def create_inputhook_tk(app):
+ def inputhook_tk():
+ while app.dooneevent(TCL_DONT_WAIT) == 1:
+ if stdin_ready():
+ break
+ return 0
+ return inputhook_tk
diff --git a/python/helpers/pydev/pydev_ipython/inputhookwx.py b/python/helpers/pydev/pydev_ipython/inputhookwx.py
new file mode 100644
index 000000000000..6640884663ad
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/inputhookwx.py
@@ -0,0 +1,167 @@
+# encoding: utf-8
+
+"""
+Enable wxPython to be used interacive by setting PyOS_InputHook.
+
+Authors: Robin Dunn, Brian Granger, Ondrej Certik
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2011 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import sys
+import signal
+import time
+from timeit import default_timer as clock
+import wx
+
+from pydev_ipython.inputhook import stdin_ready
+
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+def inputhook_wx1():
+ """Run the wx event loop by processing pending events only.
+
+ This approach seems to work, but its performance is not great as it
+ relies on having PyOS_InputHook called regularly.
+ """
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+
+ # Make a temporary event loop and process system events until
+ # there are no more waiting, then allow idle events (which
+ # will also deal with pending or posted wx events.)
+ evtloop = wx.EventLoop()
+ ea = wx.EventLoopActivator(evtloop)
+ while evtloop.Pending():
+ evtloop.Dispatch()
+ app.ProcessIdle()
+ del ea
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+class EventLoopTimer(wx.Timer):
+
+ def __init__(self, func):
+ self.func = func
+ wx.Timer.__init__(self)
+
+ def Notify(self):
+ self.func()
+
+class EventLoopRunner(object):
+
+ def Run(self, time):
+ self.evtloop = wx.EventLoop()
+ self.timer = EventLoopTimer(self.check_stdin)
+ self.timer.Start(time)
+ self.evtloop.Run()
+
+ def check_stdin(self):
+ if stdin_ready():
+ self.timer.Stop()
+ self.evtloop.Exit()
+
+def inputhook_wx2():
+ """Run the wx event loop, polling for stdin.
+
+ This version runs the wx eventloop for an undetermined amount of time,
+ during which it periodically checks to see if anything is ready on
+ stdin. If anything is ready on stdin, the event loop exits.
+
+ The argument to elr.Run controls how often the event loop looks at stdin.
+ This determines the responsiveness at the keyboard. A setting of 1000
+ enables a user to type at most 1 char per second. I have found that a
+ setting of 10 gives good keyboard response. We can shorten it further,
+ but eventually performance would suffer from calling select/kbhit too
+ often.
+ """
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+ elr = EventLoopRunner()
+ # As this time is made shorter, keyboard response improves, but idle
+ # CPU load goes up. 10 ms seems like a good compromise.
+ elr.Run(time=10) # CHANGE time here to control polling interval
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+def inputhook_wx3():
+ """Run the wx event loop by processing pending events only.
+
+ This is like inputhook_wx1, but it keeps processing pending events
+ until stdin is ready. After processing all pending events, a call to
+ time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
+ This sleep time should be tuned though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+
+ # The import of wx on Linux sets the handler for signal.SIGINT
+ # to 0. This is a bug in wx or gtk. We fix by just setting it
+ # back to the Python default.
+ if not callable(signal.getsignal(signal.SIGINT)):
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+ evtloop = wx.EventLoop()
+ ea = wx.EventLoopActivator(evtloop)
+ t = clock()
+ while not stdin_ready():
+ while evtloop.Pending():
+ t = clock()
+ evtloop.Dispatch()
+ app.ProcessIdle()
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ del ea
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+if sys.platform == 'darwin':
+ # On OSX, evtloop.Pending() always returns True, regardless of there being
+ # any events pending. As such we can't use implementations 1 or 3 of the
+ # inputhook as those depend on a pending/dispatch loop.
+ inputhook_wx = inputhook_wx2
+else:
+ # This is our default implementation
+ inputhook_wx = inputhook_wx3
diff --git a/python/helpers/pydev/pydev_ipython/qt.py b/python/helpers/pydev/pydev_ipython/qt.py
new file mode 100644
index 000000000000..71c2fbcdaaa1
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/qt.py
@@ -0,0 +1,23 @@
+""" A Qt API selector that can be used to switch between PyQt and PySide.
+
+This uses the ETS 4.0 selection pattern of:
+PySide first, PyQt with API v2. second.
+
+Do not use this if you need PyQt with the old QString/QVariant API.
+"""
+
+import os
+
+from pydev_ipython.qt_loaders import (load_qt, QT_API_PYSIDE,
+ QT_API_PYQT)
+
+QT_API = os.environ.get('QT_API', None)
+if QT_API not in [QT_API_PYSIDE, QT_API_PYQT, None]:
+ raise RuntimeError("Invalid Qt API %r, valid values are: %r, %r" %
+ (QT_API, QT_API_PYSIDE, QT_API_PYQT))
+if QT_API is None:
+ api_opts = [QT_API_PYSIDE, QT_API_PYQT]
+else:
+ api_opts = [QT_API]
+
+QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
diff --git a/python/helpers/pydev/pydev_ipython/qt_for_kernel.py b/python/helpers/pydev/pydev_ipython/qt_for_kernel.py
new file mode 100644
index 000000000000..b1c986508a04
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/qt_for_kernel.py
@@ -0,0 +1,83 @@
+""" Import Qt in a manner suitable for an IPython kernel.
+
+This is the import used for the `gui=qt` or `matplotlib=qt` initialization.
+
+Import Priority:
+
+if Qt4 has been imported anywhere else:
+ use that
+
+if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
+ use PyQt4 @v1
+
+Next, ask ETS' QT_API env variable
+
+if QT_API not set:
+ ask matplotlib via rcParams['backend.qt4']
+ if it said PyQt:
+ use PyQt4 @v1
+ elif it said PySide:
+ use PySide
+
+ else: (matplotlib said nothing)
+ # this is the default path - nobody told us anything
+ try:
+ PyQt @v1
+ except:
+ fallback on PySide
+else:
+ use PyQt @v2 or PySide, depending on QT_API
+ because ETS doesn't work with PyQt @v1.
+
+"""
+
+import os
+import sys
+
+from pydev_ipython.version import check_version
+from pydev_ipython.qt_loaders import (load_qt, QT_API_PYSIDE,
+ QT_API_PYQT, QT_API_PYQT_DEFAULT,
+ loaded_api)
+
+#Constraints placed on an imported matplotlib
+def matplotlib_options(mpl):
+ if mpl is None:
+ return
+ mpqt = mpl.rcParams.get('backend.qt4', None)
+ if mpqt is None:
+ return None
+ if mpqt.lower() == 'pyside':
+ return [QT_API_PYSIDE]
+ elif mpqt.lower() == 'pyqt4':
+ return [QT_API_PYQT_DEFAULT]
+ raise ImportError("unhandled value for backend.qt4 from matplotlib: %r" %
+ mpqt)
+
+def get_options():
+ """Return a list of acceptable QT APIs, in decreasing order of
+ preference
+ """
+ #already imported Qt somewhere. Use that
+ loaded = loaded_api()
+ if loaded is not None:
+ return [loaded]
+
+ mpl = sys.modules.get('matplotlib', None)
+
+ if mpl is not None and not check_version(mpl.__version__, '1.0.2'):
+ #1.0.1 only supports PyQt4 v1
+ return [QT_API_PYQT_DEFAULT]
+
+ if os.environ.get('QT_API', None) is None:
+ #no ETS variable. Ask mpl, then use either
+ return matplotlib_options(mpl) or [QT_API_PYQT_DEFAULT, QT_API_PYSIDE]
+
+ #ETS variable present. Will fallback to external.qt
+ return None
+
+api_opts = get_options()
+if api_opts is not None:
+ QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
+
+else: # use ETS variable
+ from pydev_ipython.qt import QtCore, QtGui, QtSvg, QT_API
diff --git a/python/helpers/pydev/pydev_ipython/qt_loaders.py b/python/helpers/pydev/pydev_ipython/qt_loaders.py
new file mode 100644
index 000000000000..f480a087d3a3
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/qt_loaders.py
@@ -0,0 +1,258 @@
+"""
+This module contains factory functions that attempt
+to return Qt submodules from the various python Qt bindings.
+
+It also protects against double-importing Qt with different
+bindings, which is unstable and likely to crash
+
+This is used primarily by qt and qt_for_kernel, and shouldn't
+be accessed directly from the outside
+"""
+import sys
+from functools import partial
+
+from pydev_ipython.version import check_version
+
+# Available APIs.
+QT_API_PYQT = 'pyqt'
+QT_API_PYQTv1 = 'pyqtv1'
+QT_API_PYQT_DEFAULT = 'pyqtdefault' # don't set SIP explicitly
+QT_API_PYSIDE = 'pyside'
+
+
+class ImportDenier(object):
+ """Import Hook that will guard against bad Qt imports
+ once IPython commits to a specific binding
+ """
+
+ def __init__(self):
+ self.__forbidden = None
+
+ def forbid(self, module_name):
+ sys.modules.pop(module_name, None)
+ self.__forbidden = module_name
+
+ def find_module(self, mod_name, pth):
+ if pth:
+ return
+ if mod_name == self.__forbidden:
+ return self
+
+ def load_module(self, mod_name):
+ raise ImportError("""
+ Importing %s disabled by IPython, which has
+ already imported an Incompatible QT Binding: %s
+ """ % (mod_name, loaded_api()))
+
+ID = ImportDenier()
+sys.meta_path.append(ID)
+
+
+def commit_api(api):
+ """Commit to a particular API, and trigger ImportErrors on subsequent
+ dangerous imports"""
+
+ if api == QT_API_PYSIDE:
+ ID.forbid('PyQt4')
+ else:
+ ID.forbid('PySide')
+
+
+def loaded_api():
+ """Return which API is loaded, if any
+
+ If this returns anything besides None,
+ importing any other Qt binding is unsafe.
+
+ Returns
+ -------
+ None, 'pyside', 'pyqt', or 'pyqtv1'
+ """
+ if 'PyQt4.QtCore' in sys.modules:
+ if qtapi_version() == 2:
+ return QT_API_PYQT
+ else:
+ return QT_API_PYQTv1
+ elif 'PySide.QtCore' in sys.modules:
+ return QT_API_PYSIDE
+ return None
+
+
+def has_binding(api):
+ """Safely check for PyQt4 or PySide, without importing
+ submodules
+
+ Parameters
+ ----------
+ api : str [ 'pyqtv1' | 'pyqt' | 'pyside' | 'pyqtdefault']
+ Which module to check for
+
+ Returns
+ -------
+ True if the relevant module appears to be importable
+ """
+ # we can't import an incomplete pyside and pyqt4
+ # this will cause a crash in sip (#1431)
+ # check for complete presence before importing
+ module_name = {QT_API_PYSIDE: 'PySide',
+ QT_API_PYQT: 'PyQt4',
+ QT_API_PYQTv1: 'PyQt4',
+ QT_API_PYQT_DEFAULT: 'PyQt4'}
+ module_name = module_name[api]
+
+ import imp
+ try:
+ #importing top level PyQt4/PySide module is ok...
+ mod = __import__(module_name)
+ #...importing submodules is not
+ imp.find_module('QtCore', mod.__path__)
+ imp.find_module('QtGui', mod.__path__)
+ imp.find_module('QtSvg', mod.__path__)
+
+ #we can also safely check PySide version
+ if api == QT_API_PYSIDE:
+ return check_version(mod.__version__, '1.0.3')
+ else:
+ return True
+ except ImportError:
+ return False
+
+
+def qtapi_version():
+ """Return which QString API has been set, if any
+
+ Returns
+ -------
+ The QString API version (1 or 2), or None if not set
+ """
+ try:
+ import sip
+ except ImportError:
+ return
+ try:
+ return sip.getapi('QString')
+ except ValueError:
+ return
+
+
+def can_import(api):
+ """Safely query whether an API is importable, without importing it"""
+ if not has_binding(api):
+ return False
+
+ current = loaded_api()
+ if api == QT_API_PYQT_DEFAULT:
+ return current in [QT_API_PYQT, QT_API_PYQTv1, None]
+ else:
+ return current in [api, None]
+
+
+def import_pyqt4(version=2):
+ """
+ Import PyQt4
+
+ Parameters
+ ----------
+ version : 1, 2, or None
+ Which QString/QVariant API to use. Set to None to use the system
+ default
+
+ ImportErrors rasied within this function are non-recoverable
+ """
+ # The new-style string API (version=2) automatically
+ # converts QStrings to Unicode Python strings. Also, automatically unpacks
+ # QVariants to their underlying objects.
+ import sip
+
+ if version is not None:
+ sip.setapi('QString', version)
+ sip.setapi('QVariant', version)
+
+ from PyQt4 import QtGui, QtCore, QtSvg
+
+ if not check_version(QtCore.PYQT_VERSION_STR, '4.7'):
+ raise ImportError("IPython requires PyQt4 >= 4.7, found %s" %
+ QtCore.PYQT_VERSION_STR)
+
+ # Alias PyQt-specific functions for PySide compatibility.
+ QtCore.Signal = QtCore.pyqtSignal
+ QtCore.Slot = QtCore.pyqtSlot
+
+ # query for the API version (in case version == None)
+ version = sip.getapi('QString')
+ api = QT_API_PYQTv1 if version == 1 else QT_API_PYQT
+ return QtCore, QtGui, QtSvg, api
+
+
+def import_pyside():
+ """
+ Import PySide
+
+ ImportErrors raised within this function are non-recoverable
+ """
+ from PySide import QtGui, QtCore, QtSvg
+ return QtCore, QtGui, QtSvg, QT_API_PYSIDE
+
+
+def load_qt(api_options):
+ """
+ Attempt to import Qt, given a preference list
+ of permissible bindings
+
+ It is safe to call this function multiple times.
+
+ Parameters
+ ----------
+ api_options: List of strings
+ The order of APIs to try. Valid items are 'pyside',
+ 'pyqt', and 'pyqtv1'
+
+ Returns
+ -------
+
+ A tuple of QtCore, QtGui, QtSvg, QT_API
+ The first three are the Qt modules. The last is the
+ string indicating which module was loaded.
+
+ Raises
+ ------
+ ImportError, if it isn't possible to import any requested
+ bindings (either becaues they aren't installed, or because
+ an incompatible library has already been installed)
+ """
+ loaders = {QT_API_PYSIDE: import_pyside,
+ QT_API_PYQT: import_pyqt4,
+ QT_API_PYQTv1: partial(import_pyqt4, version=1),
+ QT_API_PYQT_DEFAULT: partial(import_pyqt4, version=None)
+ }
+
+ for api in api_options:
+
+ if api not in loaders:
+ raise RuntimeError(
+ "Invalid Qt API %r, valid values are: %r, %r, %r, %r" %
+ (api, QT_API_PYSIDE, QT_API_PYQT,
+ QT_API_PYQTv1, QT_API_PYQT_DEFAULT))
+
+ if not can_import(api):
+ continue
+
+ #cannot safely recover from an ImportError during this
+ result = loaders[api]()
+ api = result[-1] # changed if api = QT_API_PYQT_DEFAULT
+ commit_api(api)
+ return result
+ else:
+ raise ImportError("""
+ Could not load requested Qt binding. Please ensure that
+ PyQt4 >= 4.7 or PySide >= 1.0.3 is available,
+ and only one is imported per session.
+
+ Currently-imported Qt library: %r
+ PyQt4 installed: %s
+ PySide >= 1.0.3 installed: %s
+ Tried to load: %r
+ """ % (loaded_api(),
+ has_binding(QT_API_PYQT),
+ has_binding(QT_API_PYSIDE),
+ api_options))
diff --git a/python/helpers/pydev/pydev_ipython/version.py b/python/helpers/pydev/pydev_ipython/version.py
new file mode 100644
index 000000000000..1de0047e6b4e
--- /dev/null
+++ b/python/helpers/pydev/pydev_ipython/version.py
@@ -0,0 +1,36 @@
+# encoding: utf-8
+"""
+Utilities for version comparison
+
+It is a bit ridiculous that we need these.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2013 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from distutils.version import LooseVersion
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+def check_version(v, check):
+ """check version string v >= check
+
+ If dev/prerelease tags result in TypeError for string-number comparison,
+ it is assumed that the dependency is satisfied.
+ Users on dev branches are responsible for keeping their own packages up to date.
+ """
+ try:
+ return LooseVersion(v) >= LooseVersion(check)
+ except TypeError:
+ return True
+
diff --git a/python/helpers/pydev/pydev_ipython_console.py b/python/helpers/pydev/pydev_ipython_console.py
index 6a8e0567644e..859157e022ad 100644
--- a/python/helpers/pydev/pydev_ipython_console.py
+++ b/python/helpers/pydev/pydev_ipython_console.py
@@ -82,7 +82,7 @@ class InterpreterInterface(BaseInterpreterInterface):
return ret
#Otherwise, use the default PyDev completer (to get nice icons)
- from _completer import Completer
+ from _pydev_completer import Completer
completer = Completer(self.getNamespace(), None)
completions = completer.complete(act_tok)
diff --git a/python/helpers/pydev/pydev_ipython_console_011.py b/python/helpers/pydev/pydev_ipython_console_011.py
index 15c5b85c19e0..198d40f07ec7 100644
--- a/python/helpers/pydev/pydev_ipython_console_011.py
+++ b/python/helpers/pydev/pydev_ipython_console_011.py
@@ -84,13 +84,15 @@ class PyDevFrontEnd:
self.ipython.history_manager.save_thread.pydev_do_not_trace = True #don't trace ipython history saving thread
def complete(self, string):
- if string:
- return self.ipython.complete(string)
- else:
- return self.ipython.complete(string, string, 0)
-
-
-
+ try:
+ if string:
+ return self.ipython.complete(None, line=string, cursor_pos=string.__len__())
+ else:
+ return self.ipython.complete(string, string, 0)
+ except:
+ # Silence completer exceptions
+ pass
+
def is_complete(self, string):
#Based on IPython 0.10.1
@@ -153,5 +155,5 @@ class PyDevFrontEnd:
return self.ipython.automagic
def get_greeting_msg(self):
- return 'PyDev console: using IPython %s\n' % self.version
+ return 'PyDev console: using IPython %s' % self.version
diff --git a/python/helpers/pydev/pydev_versioncheck.py b/python/helpers/pydev/pydev_versioncheck.py
new file mode 100644
index 000000000000..70bf765f47fd
--- /dev/null
+++ b/python/helpers/pydev/pydev_versioncheck.py
@@ -0,0 +1,16 @@
+import sys
+
+def versionok_for_gui():
+ ''' Return True if running Python is suitable for GUI Event Integration and deeper IPython integration '''
+ # We require Python 2.6+ ...
+ if sys.hexversion < 0x02060000:
+ return False
+ # Or Python 3.2+
+ if sys.hexversion >= 0x03000000 and sys.hexversion < 0x03020000:
+ return False
+ # Not supported under Jython nor IronPython
+ if sys.platform.startswith("java") or sys.platform.startswith('cli'):
+ return False
+
+ return True
+
diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py
index e8b8d297ff0f..7edf089d526c 100644
--- a/python/helpers/pydev/pydevconsole.py
+++ b/python/helpers/pydev/pydevconsole.py
@@ -23,10 +23,7 @@ fix_getpass.fixGetpass()
import pydevd_vars
-try:
- from pydevd_exec import Exec
-except:
- from pydevd_exec2 import Exec
+from pydev_imports import Exec
try:
if USE_LIB_COPY:
@@ -139,7 +136,7 @@ class InterpreterInterface(BaseInterpreterInterface):
def getCompletions(self, text, act_tok):
try:
- from _completer import Completer
+ from _pydev_completer import Completer
completer = Completer(self.namespace, None)
return completer.complete(act_tok)
@@ -153,7 +150,7 @@ class InterpreterInterface(BaseInterpreterInterface):
sys.exit(0)
def get_greeting_msg(self):
- return 'PyDev console: starting.\n'
+ return 'PyDev console: starting.'
def process_exec_queue(interpreter):
@@ -176,26 +173,29 @@ def process_exec_queue(interpreter):
exit()
+if 'IPYTHONENABLE' in os.environ:
+ IPYTHON = os.environ['IPYTHONENABLE'] == 'True'
+else:
+ IPYTHON = True
+
try:
try:
exitfunc = sys.exitfunc
except AttributeError:
exitfunc = None
- from pydev_ipython_console import InterpreterInterface
- IPYTHON = True
- if exitfunc is not None:
- sys.exitfunc = exitfunc
-
- else:
- try:
- delattr(sys, 'exitfunc')
- except:
- pass
+ if IPYTHON:
+ from pydev_ipython_console import InterpreterInterface
+ if exitfunc is not None:
+ sys.exitfunc = exitfunc
+ else:
+ try:
+ delattr(sys, 'exitfunc')
+ except:
+ pass
except:
IPYTHON = False
- #sys.stderr.write('PyDev console: started.\n')
- pass #IPython not available, proceed as usual.
+ pass
#=======================================================================================================================
# _DoExit
@@ -238,10 +238,14 @@ def start_server(host, port, interpreter):
if port == 0:
host = ''
- from pydev_imports import SimpleXMLRPCServer
+ try:
+ from _pydev_xmlrpc_hook import InputHookedXMLRPCServer as XMLRPCServer #@UnusedImport
+ except:
+ #I.e.: supporting the internal Jython version in PyDev to create a Jython interactive console inside Eclipse.
+ from pydev_imports import SimpleXMLRPCServer as XMLRPCServer #@Reimport
try:
- server = SimpleXMLRPCServer((host, port), logRequests=False, allow_none=True)
+ server = XMLRPCServer((host, port), logRequests=False, allow_none=True)
except:
sys.stderr.write('Error starting server with host: %s, port: %s, client_port: %s\n' % (host, port, client_port))
@@ -257,6 +261,7 @@ def start_server(host, port, interpreter):
server.register_function(interpreter.close)
server.register_function(interpreter.interrupt)
server.register_function(handshake)
+ server.register_function(interpreter.connectToDebugger)
if IPYTHON:
try:
@@ -272,7 +277,9 @@ def start_server(host, port, interpreter):
sys.stderr.write(interpreter.get_greeting_msg())
+ sys.stderr.flush()
+ interpreter.server = server
server.serve_forever()
return server
@@ -312,6 +319,8 @@ def get_completions(text, token, globals, locals):
return interpreterInterface.getCompletions(text, token)
def get_frame():
+ interpreterInterface = get_interpreter()
+
return interpreterInterface.getFrame()
def exec_code(code, globals, locals):
diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py
index 5cd96b1232ae..4a509d053619 100644
--- a/python/helpers/pydev/pydevd.py
+++ b/python/helpers/pydev/pydevd.py
@@ -1,11 +1,12 @@
#IMPORTANT: pydevd_constants must be the 1st thing defined because it'll keep a reference to the original sys._getframe
+import traceback
+
from django_debug import DjangoLineBreakpoint
from pydevd_signature import SignatureFactory
from pydevd_frame import add_exception_to_frame
import pydev_imports
from pydevd_breakpoints import * #@UnusedWildImport
import fix_getpass
-
from pydevd_comm import CMD_CHANGE_VARIABLE, \
CMD_EVALUATE_EXPRESSION, \
CMD_EXEC_EXPRESSION, \
@@ -54,17 +55,17 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \
PydevdLog, \
StartClient, \
StartServer, \
- InternalSetNextStatementThread
-
+ InternalSetNextStatementThread, ReloadCodeCommand
from pydevd_file_utils import NormFileToServer, GetFilenameAndBase
import pydevd_file_utils
import pydevd_vars
-import traceback
import pydevd_vm_type
import pydevd_tracing
import pydevd_io
import pydev_monkey
from pydevd_additional_thread_info import PyDBAdditionalThreadInfo
+from pydevd_custom_frames import CustomFramesContainer, CustomFramesContainerInit
+
if USE_LIB_COPY:
import _pydev_time as time
@@ -81,50 +82,69 @@ threadingCurrentThread = threading.currentThread
DONT_TRACE = {
- #commonly used things from the stdlib that we don't want to trace
+ # commonly used things from the stdlib that we don't want to trace
'threading.py':1,
'Queue.py':1,
'queue.py':1,
'socket.py':1,
+ 'weakref.py':1,
+ 'linecache.py':1,
+ 'threading.py':1,
#things from pydev that we don't want to trace
+ 'pydevd.py':1 ,
'pydevd_additional_thread_info.py':1,
+ 'pydevd_custom_frames.py':1,
'pydevd_comm.py':1,
+ 'pydevd_console.py':1 ,
'pydevd_constants.py':1,
'pydevd_exec.py':1,
'pydevd_exec2.py':1,
'pydevd_file_utils.py':1,
'pydevd_frame.py':1,
+ 'pydevd_import_class.py':1 ,
'pydevd_io.py':1 ,
+ 'pydevd_psyco_stub.py':1,
+ 'pydevd_reload.py':1 ,
'pydevd_resolver.py':1 ,
+ 'pydevd_stackless.py':1 ,
+ 'pydevd_traceproperty.py':1,
'pydevd_tracing.py':1 ,
'pydevd_signature.py':1,
'pydevd_utils.py':1,
'pydevd_vars.py':1,
'pydevd_vm_type.py':1,
- 'pydevd.py':1 ,
- 'pydevd_psyco_stub.py':1,
'_pydev_execfile.py':1,
'_pydev_jython_execfile.py':1
- }
+ }
if IS_PY3K:
- #if we try to trace io.py it seems it can get halted (see http://bugs.python.org/issue4716)
+ # if we try to trace io.py it seems it can get halted (see http://bugs.python.org/issue4716)
DONT_TRACE['io.py'] = 1
+ # Don't trace common encodings too
+ DONT_TRACE['cp1252.py'] = 1
+ DONT_TRACE['utf_8.py'] = 1
+
connected = False
bufferStdOutToServer = False
bufferStdErrToServer = False
remote = False
-PyDBUseLocks = True
+from _pydev_filesystem_encoding import getfilesystemencoding
+file_system_encoding = getfilesystemencoding()
def isThreadAlive(t):
try:
- alive = t.isAlive()
+ # If thread is not started yet we treat it as alive.
+ # It is required to debug threads started by start_new_thread in Python 3.4
+ if hasattr(t, '_is_stopped'):
+ alive = not t._is_stopped
+ else:
+ alive = not t.__stopped
except:
- alive = False #Workaround for Python 3.4 http://youtrack.jetbrains.com/issue/PY-12317
+ alive = t.isAlive()
return alive
#=======================================================================================================================
@@ -134,6 +154,7 @@ class PyDBCommandThread(PyDBDaemonThread):
def __init__(self, pyDb):
PyDBDaemonThread.__init__(self)
+ self._py_db_command_thread_event = pyDb._py_db_command_thread_event
self.pyDb = pyDb
self.setName('pydevd.CommandThread')
@@ -152,7 +173,8 @@ class PyDBCommandThread(PyDBDaemonThread):
self.pyDb.processInternalCommands()
except:
PydevdLog(0, 'Finishing debug communication...(2)')
- time.sleep(0.5)
+ self._py_db_command_thread_event.clear()
+ self._py_db_command_thread_event.wait(0.5)
except:
pydev_log.debug(sys.exc_info()[0])
@@ -255,6 +277,7 @@ class PydevStartNewThread(object):
pydev_start_new_thread = PydevStartNewThread()
+
#=======================================================================================================================
# PyDB
#=======================================================================================================================
@@ -272,11 +295,6 @@ class PyDB:
These are placed on the internal command queue.
"""
- RUNNING_THREAD_IDS = {} #this is a dict of thread ids pointing to thread ids. Whenever a command
- #is passed to the java end that acknowledges that a thread was created,
- #the thread id should be passed here -- and if at some time we do not find
- #that thread alive anymore, we must remove it from this list and make
- #the java side know that the thread was killed.
def __init__(self):
SetGlobalDebugger(self)
@@ -285,7 +303,7 @@ class PyDB:
self.writer = None
self.quitting = None
self.cmdFactory = NetCommandFactory()
- self._cmd_queue = {} # the hash of Queues. Key is thread id, value is thread
+ self._cmd_queue = {} # the hash of Queues. Key is thread id, value is thread
self.breakpoints = {}
self.django_breakpoints = {}
self.exception_set = {}
@@ -294,6 +312,8 @@ class PyDB:
self.readyToRun = False
self._main_lock = threading.Lock()
self._lock_running_thread_ids = threading.Lock()
+ self._py_db_command_thread_event = threading.Event()
+ CustomFramesContainer._py_db_command_thread_event = self._py_db_command_thread_event
self._finishDebuggingSession = False
self._terminationEventSent = False
self.force_post_mortem_stop = 0
@@ -328,7 +348,7 @@ class PyDB:
def initializeNetwork(self, sock):
try:
- sock.settimeout(None) # infinite, no timeouts from now on - jython does not have it
+ sock.settimeout(None) # infinite, no timeouts from now on - jython does not have it
except:
pass
self.writer = WriterThread(sock)
@@ -336,7 +356,7 @@ class PyDB:
self.writer.start()
self.reader.start()
- time.sleep(0.1) # give threads time to start
+ time.sleep(0.1) # give threads time to start
def connect(self, host, port):
if host:
@@ -350,6 +370,8 @@ class PyDB:
def getInternalQueue(self, thread_id):
""" returns internal command queue for a given thread.
if new queue is created, notify the RDB about it """
+ if thread_id.startswith('__frame__'):
+ thread_id = thread_id[thread_id.rfind('|') + 1:]
try:
return self._cmd_queue[thread_id]
except KeyError:
@@ -359,8 +381,13 @@ class PyDB:
def postInternalCommand(self, int_cmd, thread_id):
""" if thread_id is *, post to all """
if thread_id == "*":
- for k in self._cmd_queue.keys():
- self._cmd_queue[k].put(int_cmd)
+ threads = threadingEnumerate()
+ for t in threads:
+ thread_name = t.getName()
+ if not thread_name.startswith('pydevd.') or thread_name == 'pydevd.CommandThread':
+ thread_id = GetThreadId(t)
+ queue = self.getInternalQueue(thread_id)
+ queue.put(int_cmd)
else:
queue = self.getInternalQueue(thread_id)
@@ -397,17 +424,15 @@ class PyDB:
def processInternalCommands(self):
'''This function processes internal commands
'''
- curr_thread_id = GetThreadId(threadingCurrentThread())
- program_threads_alive = {}
- all_threads = threadingEnumerate()
- program_threads_dead = []
-
-
self._main_lock.acquire()
try:
self.checkOutputRedirect()
+ curr_thread_id = GetThreadId(threadingCurrentThread())
+ program_threads_alive = {}
+ all_threads = threadingEnumerate()
+ program_threads_dead = []
self._lock_running_thread_ids.acquire()
try:
for t in all_threads:
@@ -418,16 +443,16 @@ class PyDB:
if not DictContains(self._running_thread_ids, thread_id):
if not hasattr(t, 'additionalInfo'):
- #see http://sourceforge.net/tracker/index.php?func=detail&aid=1955428&group_id=85796&atid=577329
- #Let's create the additional info right away!
+ # see http://sourceforge.net/tracker/index.php?func=detail&aid=1955428&group_id=85796&atid=577329
+ # Let's create the additional info right away!
t.additionalInfo = PyDBAdditionalThreadInfo()
self._running_thread_ids[thread_id] = t
self.writer.addCommand(self.cmdFactory.makeThreadCreatedMessage(t))
queue = self.getInternalQueue(thread_id)
- cmdsToReadd = [] #some commands must be processed by the thread itself... if that's the case,
- #we will re-add the commands to the queue after executing.
+ cmdsToReadd = [] # some commands must be processed by the thread itself... if that's the case,
+ # we will re-add the commands to the queue after executing.
try:
while True:
int_cmd = queue.get(False)
@@ -470,24 +495,30 @@ class PyDB:
self._main_lock.release()
- def setTracingForUntracedContexts(self):
- #Enable the tracing for existing threads (because there may be frames being executed that
- #are currently untraced).
+ def setTracingForUntracedContexts(self, ignore_frame=None, overwrite_prev_trace=False):
+ # Enable the tracing for existing threads (because there may be frames being executed that
+ # are currently untraced).
threads = threadingEnumerate()
- for t in threads:
- if not t.getName().startswith('pydevd.'):
- #TODO: optimize so that we only actually add that tracing if it's in
- #the new breakpoint context.
- additionalInfo = None
- try:
- additionalInfo = t.additionalInfo
- except AttributeError:
- pass #that's ok, no info currently set
-
- if additionalInfo is not None:
- for frame in additionalInfo.IterFrames():
- self.SetTraceForFrameAndParents(frame)
- del frame
+ try:
+ for t in threads:
+ if not t.getName().startswith('pydevd.'):
+ # TODO: optimize so that we only actually add that tracing if it's in
+ # the new breakpoint context.
+ additionalInfo = None
+ try:
+ additionalInfo = t.additionalInfo
+ except AttributeError:
+ pass # that's ok, no info currently set
+
+ if additionalInfo is not None:
+ for frame in additionalInfo.IterFrames():
+ if frame is not ignore_frame:
+ self.SetTraceForFrameAndParents(frame, overwrite_prev_trace=overwrite_prev_trace)
+ finally:
+ frame = None
+ t = None
+ threads = None
+ additionalInfo = None
def processNetCommand(self, cmd_id, seq, text):
@@ -530,14 +561,14 @@ class PyDB:
self.postInternalCommand(int_cmd, text)
elif cmd_id == CMD_THREAD_SUSPEND:
- #Yes, thread suspend is still done at this point, not through an internal command!
+ # Yes, thread suspend is still done at this point, not through an internal command!
t = PydevdFindThreadById(text)
if t:
additionalInfo = None
try:
additionalInfo = t.additionalInfo
except AttributeError:
- pass #that's ok, no info currently set
+ pass # that's ok, no info currently set
if additionalInfo is not None:
for frame in additionalInfo.IterFrames():
@@ -545,6 +576,8 @@ class PyDB:
del frame
self.setSuspend(t, CMD_THREAD_SUSPEND)
+ elif text.startswith('__frame__:'):
+ sys.stderr.write("Can't suspend tasklet: %s\n" % (text,))
elif cmd_id == CMD_THREAD_RUN:
t = PydevdFindThreadById(text)
@@ -553,46 +586,55 @@ class PyDB:
int_cmd = InternalRunThread(thread_id)
self.postInternalCommand(int_cmd, thread_id)
+ elif text.startswith('__frame__:'):
+ sys.stderr.write("Can't make tasklet run: %s\n" % (text,))
+
+
elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN:
- #we received some command to make a single step
+ # we received some command to make a single step
t = PydevdFindThreadById(text)
if t:
thread_id = GetThreadId(t)
int_cmd = InternalStepThread(thread_id, cmd_id)
self.postInternalCommand(int_cmd, thread_id)
+ elif text.startswith('__frame__:'):
+ sys.stderr.write("Can't make tasklet step command: %s\n" % (text,))
+
+
elif cmd_id == CMD_RUN_TO_LINE or cmd_id == CMD_SET_NEXT_STATEMENT or cmd_id == CMD_SMART_STEP_INTO:
- #we received some command to make a single step
+ # we received some command to make a single step
thread_id, line, func_name = text.split('\t', 2)
t = PydevdFindThreadById(thread_id)
if t:
int_cmd = InternalSetNextStatementThread(thread_id, cmd_id, line, func_name)
self.postInternalCommand(int_cmd, thread_id)
+ elif thread_id.startswith('__frame__:'):
+ sys.stderr.write("Can't set next statement in tasklet: %s\n" % (thread_id,))
elif cmd_id == CMD_RELOAD_CODE:
- #we received some command to make a reload of a module
+ # we received some command to make a reload of a module
module_name = text.strip()
- from pydevd_reload import xreload
- if not DictContains(sys.modules, module_name):
- if '.' in module_name:
- new_module_name = module_name.split('.')[-1]
- if DictContains(sys.modules, new_module_name):
- module_name = new_module_name
-
- if not DictContains(sys.modules, module_name):
- sys.stderr.write('pydev debugger: Unable to find module to reload: "'+module_name+'".\n')
- sys.stderr.write('pydev debugger: This usually means you are trying to reload the __main__ module (which cannot be reloaded).\n')
- sys.stderr.flush()
- else:
- sys.stderr.write('pydev debugger: Reloading: '+module_name+'\n')
- sys.stderr.flush()
- xreload(sys.modules[module_name])
+ thread_id = '*' # Any thread
+
+ # Note: not going for the main thread because in this case it'd only do the load
+ # when we stopped on a breakpoint.
+ # for tid, t in self._running_thread_ids.items(): #Iterate in copy
+ # thread_name = t.getName()
+ #
+ # print thread_name, GetThreadId(t)
+ # #Note: if possible, try to reload on the main thread
+ # if thread_name == 'MainThread':
+ # thread_id = tid
+
+ int_cmd = ReloadCodeCommand(module_name, thread_id)
+ self.postInternalCommand(int_cmd, thread_id)
elif cmd_id == CMD_CHANGE_VARIABLE:
- #the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change
+ # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change
try:
thread_id, frame_id, scope, attr_and_value = text.split('\t', 3)
@@ -606,12 +648,12 @@ class PyDB:
traceback.print_exc()
elif cmd_id == CMD_GET_VARIABLE:
- #we received some command to get a variable
- #the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes*
+ # we received some command to get a variable
+ # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes*
try:
thread_id, frame_id, scopeattrs = text.split('\t', 2)
- if scopeattrs.find('\t') != -1: # there are attributes beyond scope
+ if scopeattrs.find('\t') != -1: # there are attributes beyond scope
scope, attrs = scopeattrs.split('\t', 1)
else:
scope, attrs = (scopeattrs, None)
@@ -623,8 +665,8 @@ class PyDB:
traceback.print_exc()
elif cmd_id == CMD_GET_COMPLETIONS:
- #we received some command to get a variable
- #the text is: thread_id\tframe_id\tactivation token
+ # we received some command to get a variable
+ # the text is: thread_id\tframe_id\tactivation token
try:
thread_id, frame_id, scope, act_tok = text.split('\t', 3)
@@ -641,23 +683,26 @@ class PyDB:
self.postInternalCommand(int_cmd, thread_id)
elif cmd_id == CMD_SET_BREAK:
- #func name: 'None': match anything. Empty: match global, specified: only method context.
+ # func name: 'None': match anything. Empty: match global, specified: only method context.
- #command to add some breakpoint.
+ # command to add some breakpoint.
# text is file\tline. Add to breakpoints dictionary
type, file, line, condition, expression = text.split('\t', 4)
+ if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
+ file = file.encode(file_system_encoding)
+
if condition.startswith('**FUNC**'):
func_name, condition = condition.split('\t', 1)
- #We must restore new lines and tabs as done in
- #AbstractDebugTarget.breakpointAdded
+ # We must restore new lines and tabs as done in
+ # AbstractDebugTarget.breakpointAdded
condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').\
replace("@_@TAB_CHAR@_@", '\t').strip()
func_name = func_name[8:]
else:
- func_name = 'None' #Match anything if not specified.
+ func_name = 'None' # Match anything if not specified.
file = NormFileToServer(file)
@@ -849,13 +894,29 @@ class PyDB:
cmd = self.cmdFactory.makeThreadSuspendMessage(GetThreadId(thread), frame, thread.stop_reason, message)
self.writer.addCommand(cmd)
- info = thread.additionalInfo
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ from_this_thread = []
+
+ for frame_id, custom_frame in CustomFramesContainer.custom_frames.items():
+ if custom_frame.thread_id == thread.ident:
+ # print >> sys.stderr, 'Frame created: ', frame_id
+ self.writer.addCommand(self.cmdFactory.makeCustomFrameCreatedMessage(frame_id, custom_frame.name))
+ self.writer.addCommand(self.cmdFactory.makeThreadSuspendMessage(frame_id, custom_frame.frame, CMD_THREAD_SUSPEND, ""))
+
+ from_this_thread.append(frame_id)
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
+
+
+
+ info = thread.additionalInfo
while info.pydev_state == STATE_SUSPEND and not self._finishDebuggingSession:
self.processInternalCommands()
time.sleep(0.01)
- #process any stepping instructions
+ # process any stepping instructions
if info.pydev_step_cmd == CMD_STEP_INTO:
info.pydev_step_stop = None
info.pydev_smart_step_stop = None
@@ -903,13 +964,13 @@ class PyDB:
elif info.pydev_step_cmd == CMD_STEP_RETURN:
back_frame = frame.f_back
if back_frame is not None:
- #steps back to the same frame (in a return call it will stop in the 'back frame' for the user)
+ # steps back to the same frame (in a return call it will stop in the 'back frame' for the user)
info.pydev_step_stop = frame
self.SetTraceForFrameAndParents(frame)
else:
- #No back frame?!? -- this happens in jython when we have some frame created from an awt event
- #(the previous frame would be the awt event, but this doesn't make part of 'jython', only 'java')
- #so, if we're doing a step return in this situation, it's the same as just making it run
+ # No back frame?!? -- this happens in jython when we have some frame created from an awt event
+ # (the previous frame would be the awt event, but this doesn't make part of 'jython', only 'java')
+ # so, if we're doing a step return in this situation, it's the same as just making it run
info.pydev_step_stop = None
info.pydev_step_cmd = None
info.pydev_state = STATE_RUN
@@ -918,6 +979,15 @@ class PyDB:
cmd = self.cmdFactory.makeThreadRunMessage(GetThreadId(thread), info.pydev_step_cmd)
self.writer.addCommand(cmd)
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ # The ones that remained on last_running must now be removed.
+ for frame_id in from_this_thread:
+ # print >> sys.stderr, 'Removing created frame: ', frame_id
+ self.writer.addCommand(self.cmdFactory.makeThreadKilledMessage(frame_id))
+
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
def handle_post_mortem_stop(self, additionalInfo, t):
pydev_log.debug("We are stopping in post-mortem\n")
@@ -949,7 +1019,6 @@ class PyDB:
try:
if self._finishDebuggingSession and not self._terminationEventSent:
#that was not working very well because jython gave some socket errors
- t = threadingCurrentThread()
try:
threads = threadingEnumerate()
for t in threads:
@@ -1005,19 +1074,16 @@ class PyDB:
if is_file_to_ignore:
return None
- #each new frame...
+ # each new frame...
return additionalInfo.CreateDbFrame((self, filename, additionalInfo, t, frame)).trace_dispatch(frame, event, arg)
except SystemExit:
return None
- except TypeError:
- return None
-
except Exception:
- #Log it
+ # Log it
if traceback is not None:
- #This can actually happen during the interpreter shutdown in Python 2.7
+ # This can actually happen during the interpreter shutdown in Python 2.7
traceback.print_exc()
return None
@@ -1030,8 +1096,8 @@ class PyDB:
doWaitSuspend = psyco.proxy(doWaitSuspend)
getInternalQueue = psyco.proxy(getInternalQueue)
except ImportError:
- if hasattr(sys, 'exc_clear'): #jython does not have it
- sys.exc_clear() #don't keep the traceback (let's keep it clear for when we go to the point of executing client code)
+ if hasattr(sys, 'exc_clear'): # jython does not have it
+ sys.exc_clear() # don't keep the traceback (let's keep it clear for when we go to the point of executing client code)
if not IS_PY3K and not IS_PY27 and not IS_64_BITS and not sys.platform.startswith("java") and not sys.platform.startswith("cli"):
sys.stderr.write("pydev debugger: warning: psyco not available for speedups (the debugger will still work correctly, but a bit slower)\n")
@@ -1039,15 +1105,15 @@ class PyDB:
- def SetTraceForFrameAndParents(self, frame, also_add_to_passed_frame=True, overwrite_prev=False):
+ def SetTraceForFrameAndParents(self, frame, also_add_to_passed_frame=True, overwrite_prev_trace=False):
dispatch_func = self.trace_dispatch
if also_add_to_passed_frame:
- self.update_trace(frame, dispatch_func, overwrite_prev)
+ self.update_trace(frame, dispatch_func, overwrite_prev_trace)
frame = frame.f_back
while frame:
- self.update_trace(frame, dispatch_func, overwrite_prev)
+ self.update_trace(frame, dispatch_func, overwrite_prev_trace)
frame = frame.f_back
del frame
@@ -1068,17 +1134,49 @@ class PyDB:
frame = frame.f_back
del frame
+ def prepareToRun(self):
+ ''' Shared code to prepare debugging by installing traces and registering threads '''
+
+ # for completeness, we'll register the pydevd.reader & pydevd.writer threads
+ net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.reader" id="-1"/></xml>')
+ self.writer.addCommand(net)
+ net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.writer" id="-1"/></xml>')
+ self.writer.addCommand(net)
+
+ pydevd_tracing.SetTrace(self.trace_dispatch)
+ self.patch_threads()
- def run(self, file, globals=None, locals=None):
+ PyDBCommandThread(self).start()
+ PyDBCheckAliveThread(self).start()
+
+ def patch_threads(self):
+ try:
+ # not available in jython!
+ threading.settrace(self.trace_dispatch) # for all future threads
+ except:
+ pass
+
+ try:
+ thread.start_new_thread = pydev_start_new_thread
+ thread.start_new = pydev_start_new_thread
+ except:
+ pass
+
+
+ def run(self, file, globals=None, locals=None, set_trace=True):
+ if os.path.isdir(file):
+ new_target = os.path.join(file, '__main__.py')
+ if os.path.isfile(new_target):
+ file = new_target
if globals is None:
- #patch provided by: Scott Schlesier - when script is run, it does not
- #use globals from pydevd:
- #This will prevent the pydevd script from contaminating the namespace for the script to be debugged
+ # patch provided by: Scott Schlesier - when script is run, it does not
+ # use globals from pydevd:
+ # This will prevent the pydevd script from contaminating the namespace for the script to be debugged
- #pretend pydevd is not the main module, and
- #convince the file to be debugged that it was loaded as main
+ # pretend pydevd is not the main module, and
+ # convince the file to be debugged that it was loaded as main
sys.modules['pydevd'] = sys.modules['__main__']
sys.modules['pydevd'].__name__ = 'pydevd'
@@ -1093,61 +1191,39 @@ class PyDB:
try:
globals['__builtins__'] = __builtins__
except NameError:
- pass #Not there on Jython...
+ pass # Not there on Jython...
if locals is None:
locals = globals
- #Predefined (writable) attributes: __name__ is the module's name;
- #__doc__ is the module's documentation string, or None if unavailable;
- #__file__ is the pathname of the file from which the module was loaded,
- #if it was loaded from a file. The __file__ attribute is not present for
- #C modules that are statically linked into the interpreter; for extension modules
- #loaded dynamically from a shared library, it is the pathname of the shared library file.
+ if set_trace:
+ # Predefined (writable) attributes: __name__ is the module's name;
+ # __doc__ is the module's documentation string, or None if unavailable;
+ # __file__ is the pathname of the file from which the module was loaded,
+ # if it was loaded from a file. The __file__ attribute is not present for
+ # C modules that are statically linked into the interpreter; for extension modules
+ # loaded dynamically from a shared library, it is the pathname of the shared library file.
- #I think this is an ugly hack, bug it works (seems to) for the bug that says that sys.path should be the same in
- #debug and run.
- if m.__file__.startswith(sys.path[0]):
- #print >> sys.stderr, 'Deleting: ', sys.path[0]
- del sys.path[0]
+ # I think this is an ugly hack, bug it works (seems to) for the bug that says that sys.path should be the same in
+ # debug and run.
+ if m.__file__.startswith(sys.path[0]):
+ # print >> sys.stderr, 'Deleting: ', sys.path[0]
+ del sys.path[0]
- #now, the local directory has to be added to the pythonpath
- #sys.path.insert(0, os.getcwd())
- #Changed: it's not the local directory, but the directory of the file launched
- #The file being run ust be in the pythonpath (even if it was not before)
- sys.path.insert(0, os.path.split(file)[0])
-
- # for completness, we'll register the pydevd.reader & pydevd.writer threads
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.reader" id="-1"/></xml>')
- self.writer.addCommand(net)
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.writer" id="-1"/></xml>')
- self.writer.addCommand(net)
-
- pydevd_tracing.SetTrace(self.trace_dispatch)
- try:
- #not available in jython!
- threading.settrace(self.trace_dispatch) # for all future threads
- except:
- pass
+ # now, the local directory has to be added to the pythonpath
+ # sys.path.insert(0, os.getcwd())
+ # Changed: it's not the local directory, but the directory of the file launched
+ # The file being run ust be in the pythonpath (even if it was not before)
+ sys.path.insert(0, os.path.split(file)[0])
- try:
- thread.start_new_thread = pydev_start_new_thread
- thread.start_new = pydev_start_new_thread
- except:
- pass
+ self.prepareToRun()
- while not self.readyToRun:
- time.sleep(0.1) # busy wait until we receive run command
+ while not self.readyToRun:
+ time.sleep(0.1) # busy wait until we receive run command
- PyDBCommandThread(debugger).start()
- PyDBCheckAliveThread(debugger).start()
- if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON and sys.version_info[1] == 5 and sys.version_info[2] >= 3:
- from _pydev_jython_execfile import jython_execfile
- jython_execfile(sys.argv)
- else:
- pydev_imports.execfile(file, globals, locals) #execute the script
+ pydev_imports.execfile(file, globals, locals) # execute the script
def exiting(self):
sys.stdout.flush()
@@ -1239,27 +1315,79 @@ def initStderrRedirect():
sys.stderrBuf = pydevd_io.IOBuf()
sys.stderr = pydevd_io.IORedirector(sys.stderr, sys.stderrBuf) #@UndefinedVariable
-def settrace(host='localhost', stdoutToServer=False, stderrToServer=False, port=5678, suspend=True, trace_only_current_thread=False, overwrite_prev_trace=False):
+#=======================================================================================================================
+# settrace
+#=======================================================================================================================
+def settrace(
+ host=None,
+ stdoutToServer=False,
+ stderrToServer=False,
+ port=5678,
+ suspend=True,
+ trace_only_current_thread=False,
+ overwrite_prev_trace=False,
+ patch_multiprocessing=False,
+ ):
'''Sets the tracing function with the pydev debug function and initializes needed facilities.
- @param host: the user may specify another host, if the debug server is not in the same machine
+ @param host: the user may specify another host, if the debug server is not in the same machine (default is the local
+ host)
+
@param stdoutToServer: when this is true, the stdout is passed to the debug server
+
@param stderrToServer: when this is true, the stderr is passed to the debug server
so that they are printed in its console and not in this process console.
+
@param port: specifies which port to use for communicating with the server (note that the server must be started
in the same port). @note: currently it's hard-coded at 5678 in the client
+
@param suspend: whether a breakpoint should be emulated as soon as this function is called.
- @param trace_only_current_thread: determines if only the current thread will be traced or all future threads will also have the tracing enabled.
+
+ @param trace_only_current_thread: determines if only the current thread will be traced or all current and future
+ threads will also have the tracing enabled.
+
+ @param overwrite_prev_trace: if True we'll reset the frame.f_trace of frames which are already being traced
+
+ @param patch_multiprocessing: if True we'll patch the functions which create new processes so that launched
+ processes are debugged.
'''
_set_trace_lock.acquire()
try:
- _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_only_current_thread, overwrite_prev_trace)
+ _locked_settrace(
+ host,
+ stdoutToServer,
+ stderrToServer,
+ port,
+ suspend,
+ trace_only_current_thread,
+ overwrite_prev_trace,
+ patch_multiprocessing,
+ )
finally:
_set_trace_lock.release()
+
+
_set_trace_lock = threading.Lock()
-def _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_only_current_thread, overwrite_prev_trace):
+def _locked_settrace(
+ host,
+ stdoutToServer,
+ stderrToServer,
+ port,
+ suspend,
+ trace_only_current_thread,
+ overwrite_prev_trace,
+ patch_multiprocessing,
+ ):
+ if patch_multiprocessing:
+ try:
+ import pydev_monkey #Jython 2.1 can't use it...
+ except:
+ pass
+ else:
+ pydev_monkey.patch_new_process_functions()
+
if host is None:
import pydev_localhost
host = pydev_localhost.get_localhost()
@@ -1267,19 +1395,17 @@ def _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_
global connected
global bufferStdOutToServer
global bufferStdErrToServer
- global remote
-
- remote = True
if not connected :
- connected = True
- bufferStdOutToServer = stdoutToServer
- bufferStdErrToServer = stderrToServer
-
pydevd_vm_type.SetupType()
debugger = PyDB()
- debugger.connect(host, port)
+ debugger.connect(host, port) # Note: connect can raise error.
+
+ # Mark connected only if it actually succeeded.
+ connected = True
+ bufferStdOutToServer = stdoutToServer
+ bufferStdErrToServer = stderrToServer
net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.reader" id="-1"/></xml>')
debugger.writer.addCommand(net)
@@ -1292,7 +1418,16 @@ def _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_
if bufferStdErrToServer:
initStderrRedirect()
- debugger.SetTraceForFrameAndParents(GetFrame(), False, overwrite_prev=overwrite_prev_trace)
+ debugger.SetTraceForFrameAndParents(GetFrame(), False, overwrite_prev_trace=overwrite_prev_trace)
+
+
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ for _frameId, custom_frame in CustomFramesContainer.custom_frames.items():
+ debugger.SetTraceForFrameAndParents(custom_frame.frame, False)
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
+
t = threadingCurrentThread()
try:
@@ -1302,36 +1437,29 @@ def _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_
t.additionalInfo = additionalInfo
while not debugger.readyToRun:
- time.sleep(0.1) # busy wait until we receive run command
+ time.sleep(0.1) # busy wait until we receive run command
- if suspend:
- debugger.setSuspend(t, CMD_SET_BREAK)
-
- #note that we do that through pydevd_tracing.SetTrace so that the tracing
- #is not warned to the user!
+ # note that we do that through pydevd_tracing.SetTrace so that the tracing
+ # is not warned to the user!
pydevd_tracing.SetTrace(debugger.trace_dispatch)
if not trace_only_current_thread:
- #Trace future threads?
- try:
- #not available in jython!
- threading.settrace(debugger.trace_dispatch) # for all future threads
- except:
- pass
+ # Trace future threads?
+ debugger.patch_threads()
- try:
- thread.start_new_thread = pydev_start_new_thread
- thread.start_new = pydev_start_new_thread
- except:
- pass
+ # As this is the first connection, also set tracing for any untraced threads
+ debugger.setTracingForUntracedContexts(ignore_frame=GetFrame(), overwrite_prev_trace=overwrite_prev_trace)
sys.exitfunc = exit_hook
+ #Suspend as the last thing after all tracing is in place.
+ if suspend:
+ debugger.setSuspend(t, CMD_SET_BREAK)
PyDBCommandThread(debugger).start()
PyDBCheckAliveThread(debugger).start()
else:
- #ok, we're already in debug mode, with all set, so, let's just set the break
+ # ok, we're already in debug mode, with all set, so, let's just set the break
debugger = GetGlobalDebugger()
debugger.SetTraceForFrameAndParents(GetFrame(), False)
@@ -1346,22 +1474,14 @@ def _locked_settrace(host, stdoutToServer, stderrToServer, port, suspend, trace_
pydevd_tracing.SetTrace(debugger.trace_dispatch)
if not trace_only_current_thread:
- #Trace future threads?
- try:
- #not available in jython!
- threading.settrace(debugger.trace_dispatch) # for all future threads
- except:
- pass
+ # Trace future threads?
+ debugger.patch_threads()
- try:
- thread.start_new_thread = pydev_start_new_thread
- thread.start_new = pydev_start_new_thread
- except:
- pass
if suspend:
debugger.setSuspend(t, CMD_SET_BREAK)
+
def stoptrace():
global connected
if connected:
@@ -1447,7 +1567,17 @@ def settrace_forked():
if port is not None:
global connected
connected = False
- settrace(host, port=port, suspend=False, overwrite_prev_trace=True)
+
+ CustomFramesContainerInit()
+
+ settrace(
+ host,
+ port=port,
+ suspend=False,
+ trace_only_current_thread=False,
+ overwrite_prev_trace=True,
+ patch_multiprocessing=True,
+ )
#=======================================================================================================================
# main
#=======================================================================================================================
@@ -1461,23 +1591,8 @@ if __name__ == '__main__':
usage(1)
- #as to get here all our imports are already resolved, the psyco module can be
- #changed and we'll still get the speedups in the debugger, as those functions
- #are already compiled at this time.
- try:
- import psyco
- except ImportError:
- if hasattr(sys, 'exc_clear'): #jython does not have it
- sys.exc_clear() #don't keep the traceback -- clients don't want to see it
- pass #that's ok, no need to mock psyco if it's not available anyways
- else:
- #if it's available, let's change it for a stub (pydev already made use of it)
- import pydevd_psyco_stub
- sys.modules['psyco'] = pydevd_psyco_stub
-
fix_getpass.fixGetpass()
-
pydev_log.debug("Executing file %s" % setup['file'])
pydev_log.debug("arguments: %s"% str(sys.argv))
@@ -1493,6 +1608,8 @@ if __name__ == '__main__':
port = setup['port']
host = setup['client']
+ f = setup['file']
+ fix_app_engine_debug = False
if setup['multiproc']:
pydev_log.debug("Started in multiproc mode\n")
@@ -1523,6 +1640,83 @@ if __name__ == '__main__':
pydev_log.error("Error patching process functions\n")
traceback.print_exc()
+ # Only do this patching if we're not running with multiprocess turned on.
+ if f.find('dev_appserver.py') != -1:
+ if os.path.basename(f).startswith('dev_appserver.py'):
+ appserver_dir = os.path.dirname(f)
+ version_file = os.path.join(appserver_dir, 'VERSION')
+ if os.path.exists(version_file):
+ try:
+ stream = open(version_file, 'r')
+ try:
+ for line in stream.read().splitlines():
+ line = line.strip()
+ if line.startswith('release:'):
+ line = line[8:].strip()
+ version = line.replace('"', '')
+ version = version.split('.')
+ if int(version[0]) > 1:
+ fix_app_engine_debug = True
+
+ elif int(version[0]) == 1:
+ if int(version[1]) >= 7:
+ # Only fix from 1.7 onwards
+ fix_app_engine_debug = True
+ break
+ finally:
+ stream.close()
+ except:
+ traceback.print_exc()
+
+ try:
+ # In the default run (i.e.: run directly on debug mode), we try to patch stackless as soon as possible
+ # on a run where we have a remote debug, we may have to be more careful because patching stackless means
+ # that if the user already had a stackless.set_schedule_callback installed, he'd loose it and would need
+ # to call it again (because stackless provides no way of getting the last function which was registered
+ # in set_schedule_callback).
+ #
+ # So, ideally, if there's an application using stackless and the application wants to use the remote debugger
+ # and benefit from stackless debugging, the application itself must call:
+ #
+ # import pydevd_stackless
+ # pydevd_stackless.patch_stackless()
+ #
+ # itself to be able to benefit from seeing the tasklets created before the remote debugger is attached.
+ import pydevd_stackless
+ pydevd_stackless.patch_stackless()
+ except:
+ pass # It's ok not having stackless there...
+
+ if fix_app_engine_debug:
+ sys.stderr.write("pydev debugger: google app engine integration enabled\n")
+ curr_dir = os.path.dirname(__file__)
+ app_engine_startup_file = os.path.join(curr_dir, 'pydev_app_engine_debug_startup.py')
+
+ sys.argv.insert(1, '--python_startup_script=' + app_engine_startup_file)
+ import json
+ setup['pydevd'] = __file__
+ sys.argv.insert(2, '--python_startup_args=%s' % json.dumps(setup),)
+ sys.argv.insert(3, '--automatic_restart=no')
+ sys.argv.insert(4, '--max_module_instances=1')
+
+ debugger = PyDB()
+ # Run the dev_appserver
+ debugger.run(setup['file'], None, None, set_trace=False)
+
+ else:
+ # as to get here all our imports are already resolved, the psyco module can be
+ # changed and we'll still get the speedups in the debugger, as those functions
+ # are already compiled at this time.
+ try:
+ import psyco
+ except ImportError:
+ if hasattr(sys, 'exc_clear'): # jython does not have it
+ sys.exc_clear() # don't keep the traceback -- clients don't want to see it
+ pass # that's ok, no need to mock psyco if it's not available anyways
+ else:
+ # if it's available, let's change it for a stub (pydev already made use of it)
+ import pydevd_psyco_stub
+ sys.modules['psyco'] = pydevd_psyco_stub
debugger = PyDB()
diff --git a/python/helpers/pydev/pydevd_additional_thread_info.py b/python/helpers/pydev/pydevd_additional_thread_info.py
index d2d3fffbce82..1b0fc2cdd633 100644
--- a/python/helpers/pydev/pydevd_additional_thread_info.py
+++ b/python/helpers/pydev/pydevd_additional_thread_info.py
@@ -118,7 +118,7 @@ class PyDBAdditionalThreadInfoWithoutCurrentFramesSupport(AbstractPyDBAdditional
try:
ret.append(weak_db_frame().frame)
except AttributeError:
- pass #ok, garbage-collected already
+ pass # ok, garbage-collected already
return ret
finally:
self._release_lock()
@@ -136,13 +136,11 @@ if hasattr(sys, '_current_frames'):
PyDBAdditionalThreadInfo = PyDBAdditionalThreadInfoWithCurrentFramesSupport
else:
try:
- import threadframe
+ import threadframe #@UnresolvedImport
sys._current_frames = threadframe.dict
- assert sys._current_frames is threadframe.dict #Just check if it was correctly set
+ assert sys._current_frames is threadframe.dict #Just check if it was correctly set
PyDBAdditionalThreadInfo = PyDBAdditionalThreadInfoWithCurrentFramesSupport
except:
#If all fails, let's use the support without frames
PyDBAdditionalThreadInfo = PyDBAdditionalThreadInfoWithoutCurrentFramesSupport
- sys.stderr.write("pydev debugger: warning: sys._current_frames is not supported in Python 2.4, it is recommended to install threadframe module\n")
- sys.stderr.write("pydev debugger: warning: See http://majid.info/blog/threadframe-multithreaded-stack-frame-extraction-for-python/\n")
diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py
index b7505362c0dc..9d4f2e78b94d 100644
--- a/python/helpers/pydev/pydevd_comm.py
+++ b/python/helpers/pydev/pydevd_comm.py
@@ -89,22 +89,21 @@ else:
from socket import SHUT_RD, SHUT_WR
try:
- from urllib import quote
+ from urllib import quote, quote_plus, unquote, unquote_plus
except:
- from urllib.parse import quote #@Reimport @UnresolvedImport
-
+ from urllib.parse import quote, quote_plus, unquote, unquote_plus #@Reimport @UnresolvedImport
+import pydevconsole
import pydevd_vars
import pydevd_tracing
import pydevd_vm_type
import pydevd_file_utils
import traceback
-from pydevd_utils import *
-from pydevd_utils import quote_smart as quote
+from pydevd_utils import quote_smart as quote, compare_object_attrs, cmp_to_key, to_string
import pydev_log
-
+import _pydev_completer
from pydevd_tracing import GetExceptionTracebackStr
-import pydevconsole
+
CMD_RUN = 101
@@ -182,6 +181,8 @@ MAX_IO_MSG_SIZE = 1000 #if the io is too big, we'll not send all (could make th
VERSION_STRING = "@@BUILD_NUMBER@@"
+from _pydev_filesystem_encoding import getfilesystemencoding
+file_system_encoding = getfilesystemencoding()
#--------------------------------------------------------------------------------------------------- UTILITIES
@@ -290,7 +291,11 @@ class ReaderThread(PyDBDaemonThread):
if not self.killReceived:
self.handleExcept()
return #Finished communication.
- if IS_PY3K:
+
+ #Note: the java backend is always expected to pass utf-8 encoded strings. We now work with unicode
+ #internally and thus, we may need to convert to the actual encoding where needed (i.e.: filenames
+ #on python 2 may need to be converted to the filesystem encoding).
+ if hasattr(r, 'decode'):
r = r.decode('utf-8')
buffer += r
@@ -375,10 +380,10 @@ class WriterThread(PyDBDaemonThread):
out = cmd.getOutgoing()
if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
- out_message = 'Sending cmd: '
- out_message += ID_TO_MEANING.get(out[:3], 'UNKNOWN')
+ out_message = 'sending cmd --> '
+ out_message += "%20s" % ID_TO_MEANING.get(out[:3], 'UNKNOWN')
out_message += ' '
- out_message += out
+ out_message += unquote(unquote(out)).replace('\n', ' ')
try:
sys.stderr.write('%s\n' % (out_message,))
except:
@@ -501,6 +506,13 @@ class NetCommandFactory:
cmdText = "<xml>" + self.threadToXML(thread) + "</xml>"
return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
+
+ def makeCustomFrameCreatedMessage(self, frameId, frameDescription):
+ frameDescription = pydevd_vars.makeValidXmlValue(frameDescription)
+ cmdText = '<xml><thread name="%s" id="%s"/></xml>' % (frameDescription, frameId)
+ return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
+
+
def makeListThreadsMessage(self, seq):
""" returns thread listing as XML """
try:
@@ -588,6 +600,10 @@ class NetCommandFactory:
filename, base = pydevd_file_utils.GetFilenameAndBase(curFrame)
myFile = pydevd_file_utils.NormFileToClient(filename)
+ if file_system_encoding.lower() != "utf-8" and hasattr(myFile, "decode"):
+ # myFile is a byte string encoded using the file system encoding
+ # convert it to utf8
+ myFile = myFile.decode(file_system_encoding).encode("utf-8")
#print "file is ", myFile
#myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
@@ -687,6 +703,54 @@ class InternalThreadCommand:
def doIt(self, dbg):
raise NotImplementedError("you have to override doIt")
+
+class ReloadCodeCommand(InternalThreadCommand):
+
+
+ def __init__(self, module_name, thread_id):
+ self.thread_id = thread_id
+ self.module_name = module_name
+ self.executed = False
+ self.lock = threading.Lock()
+
+
+ def canBeExecutedBy(self, thread_id):
+ if self.thread_id == '*':
+ return True #Any thread can execute it!
+
+ return InternalThreadCommand.canBeExecutedBy(self, thread_id)
+
+
+ def doIt(self, dbg):
+ self.lock.acquire()
+ try:
+ if self.executed:
+ return
+ self.executed = True
+ finally:
+ self.lock.release()
+
+ module_name = self.module_name
+ if not DictContains(sys.modules, module_name):
+ if '.' in module_name:
+ new_module_name = module_name.split('.')[-1]
+ if DictContains(sys.modules, new_module_name):
+ module_name = new_module_name
+
+ if not DictContains(sys.modules, module_name):
+ sys.stderr.write('pydev debugger: Unable to find module to reload: "' + module_name + '".\n')
+ # Too much info...
+ # sys.stderr.write('pydev debugger: This usually means you are trying to reload the __main__ module (which cannot be reloaded).\n')
+
+ else:
+ sys.stderr.write('pydev debugger: Start reloading module: "' + module_name + '" ... \n')
+ import pydevd_reload
+ if pydevd_reload.xreload(sys.modules[module_name]):
+ sys.stderr.write('pydev debugger: reload finished\n')
+ else:
+ sys.stderr.write('pydev debugger: reload finished without applying any change\n')
+
+
#=======================================================================================================================
# InternalTerminateThread
#=======================================================================================================================
@@ -876,6 +940,49 @@ class InternalEvaluateExpression(InternalThreadCommand):
dbg.writer.addCommand(cmd)
#=======================================================================================================================
+# InternalGetCompletions
+#=======================================================================================================================
+class InternalGetCompletions(InternalThreadCommand):
+ """ Gets the completions in a given scope """
+
+ def __init__(self, seq, thread_id, frame_id, act_tok):
+ self.sequence = seq
+ self.thread_id = thread_id
+ self.frame_id = frame_id
+ self.act_tok = act_tok
+
+
+ def doIt(self, dbg):
+ """ Converts request into completions """
+ try:
+ remove_path = None
+ try:
+
+ frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
+ if frame is not None:
+
+
+ msg = _pydev_completer.GenerateCompletionsAsXML(frame, self.act_tok)
+
+ cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg)
+ dbg.writer.addCommand(cmd)
+ else:
+ cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "InternalGetCompletions: Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id))
+ dbg.writer.addCommand(cmd)
+
+
+ finally:
+ if remove_path is not None:
+ sys.path.remove(remove_path)
+
+ except:
+ exc = GetExceptionTracebackStr()
+ sys.stderr.write('%s\n' % (exc,))
+ cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc)
+ dbg.writer.addCommand(cmd)
+
+
+#=======================================================================================================================
# InternalConsoleExec
#=======================================================================================================================
class InternalConsoleExec(InternalThreadCommand):
@@ -914,87 +1021,6 @@ class InternalConsoleExec(InternalThreadCommand):
sys.stderr.flush()
sys.stdout.flush()
-#=======================================================================================================================
-# InternalGetCompletions
-#=======================================================================================================================
-class InternalGetCompletions(InternalThreadCommand):
- """ Gets the completions in a given scope """
-
- def __init__(self, seq, thread_id, frame_id, act_tok):
- self.sequence = seq
- self.thread_id = thread_id
- self.frame_id = frame_id
- self.act_tok = act_tok
-
-
- def doIt(self, dbg):
- """ Converts request into completions """
- try:
- remove_path = None
- try:
- import _completer
- except:
- try:
- path = os.environ['PYDEV_COMPLETER_PYTHONPATH']
- except :
- path = os.path.dirname(__file__)
- sys.path.append(path)
- remove_path = path
- try:
- import _completer
- except :
- pass
-
- try:
-
- frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
- if frame is not None:
-
- #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
- #(Names not resolved in generator expression in method)
- #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
- updated_globals = {}
- updated_globals.update(frame.f_globals)
- updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
- locals = frame.f_locals
- else:
- updated_globals = {}
- locals = {}
-
-
- if pydevconsole.IPYTHON:
- completions = pydevconsole.get_completions(self.act_tok, self.act_tok, updated_globals, locals)
- else:
- try:
- completer = _completer.Completer(updated_globals, None)
- #list(tuple(name, descr, parameters, type))
- completions = completer.complete(self.act_tok)
- except :
- completions = []
-
-
- def makeValid(s):
- return pydevd_vars.makeValidXmlValue(pydevd_vars.quote(s, '/>_= \t'))
-
- msg = "<xml>"
-
- for comp in completions:
- msg += '<comp p0="%s" p1="%s" p2="%s" p3="%s"/>' % (makeValid(comp[0]), makeValid(comp[1]), makeValid(comp[2]), makeValid(comp[3]),)
- msg += "</xml>"
-
- cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg)
- dbg.writer.addCommand(cmd)
-
- finally:
- if remove_path is not None:
- sys.path.remove(remove_path)
-
- except:
- exc = GetExceptionTracebackStr()
- sys.stderr.write('%s\n' % (exc,))
- cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error getting completion " + exc)
- dbg.writer.addCommand(cmd)
-
#=======================================================================================================================
# PydevdFindThreadById
@@ -1004,7 +1030,8 @@ def PydevdFindThreadById(thread_id):
# there was a deadlock here when I did not remove the tracing function when thread was dead
threads = threading.enumerate()
for i in threads:
- if thread_id == GetThreadId(i):
+ tid = GetThreadId(i)
+ if thread_id == tid or thread_id.endswith('|' + tid):
return i
sys.stderr.write("Could not find thread %s\n" % thread_id)
diff --git a/python/helpers/pydev/pydevd_constants.py b/python/helpers/pydev/pydevd_constants.py
index 5e78e15d3a19..71fe4aed2505 100644
--- a/python/helpers/pydev/pydevd_constants.py
+++ b/python/helpers/pydev/pydevd_constants.py
@@ -59,7 +59,7 @@ try:
elif sys.version_info[0] == 2 and sys.version_info[1] == 4:
IS_PY24 = True
except AttributeError:
- pass #Not all versions have sys.version_info
+ pass #Not all versions have sys.version_info
try:
IS_64_BITS = sys.maxsize > 2 ** 32
@@ -85,10 +85,7 @@ _nextThreadIdLock = threading.Lock()
# Jython?
#=======================================================================================================================
try:
- import org.python.core.PyDictionary #@UnresolvedImport @UnusedImport -- just to check if it could be valid
-
- def DictContains(d, key):
- return d.has_key(key)
+ DictContains = dict.has_key
except:
try:
#Py3k does not have has_key anymore, and older versions don't have __contains__
@@ -99,6 +96,19 @@ except:
except NameError:
def DictContains(d, key):
return d.has_key(key)
+#=======================================================================================================================
+# Jython?
+#=======================================================================================================================
+try:
+ DictPop = dict.pop
+except:
+ def DictPop(d, key, default=None):
+ try:
+ ret = d[key]
+ del d[key]
+ return ret
+ except:
+ return default
try:
@@ -193,6 +203,9 @@ class Null:
return self
def __getattr__(self, mname):
+ if len(mname) > 4 and mname[:2] == '__' and mname[-2:] == '__':
+ # Don't pretend to implement special method names.
+ raise AttributeError(mname)
return self
def __setattr__(self, name, value):
@@ -222,6 +235,30 @@ class Null:
def __nonzero__(self):
return 0
+ def __iter__(self):
+ return iter(())
+
+
+def call_only_once(func):
+ '''
+ To be used as a decorator
+
+ @call_only_once
+ def func():
+ print 'Calling func only this time'
+
+ Actually, in PyDev it must be called as:
+
+ func = call_only_once(func) to support older versions of Python.
+ '''
+ def new_func(*args, **kwargs):
+ if not new_func._called:
+ new_func._called = True
+ return func(*args, **kwargs)
+
+ new_func._called = False
+ return new_func
+
if __name__ == '__main__':
if Null():
sys.stdout.write('here\n')
diff --git a/python/helpers/pydev/pydevd_custom_frames.py b/python/helpers/pydev/pydevd_custom_frames.py
new file mode 100644
index 000000000000..e259356b8336
--- /dev/null
+++ b/python/helpers/pydev/pydevd_custom_frames.py
@@ -0,0 +1,121 @@
+from pydevd_constants import * #@UnusedWildImport
+from pydevd_file_utils import GetFilenameAndBase
+threadingCurrentThread = threading.currentThread
+
+DEBUG = False
+
+#=======================================================================================================================
+# CustomFramesContainer
+#=======================================================================================================================
+class CustomFramesContainer:
+ pass
+
+
+def CustomFramesContainerInit(): #Note: no staticmethod on jython 2.1 (so, use free-function)
+
+ CustomFramesContainer.custom_frames_lock = threading.Lock()
+
+ # custom_frames can only be accessed if properly locked with custom_frames_lock!
+ # Key is a string identifying the frame (as well as the thread it belongs to).
+ # Value is a CustomFrame.
+ #
+ CustomFramesContainer.custom_frames = {}
+
+ # Only to be used in this module
+ CustomFramesContainer._next_frame_id = 0
+
+ # This is the event we must set to release an internal process events. It's later set by the actual debugger
+ # when we do create the debugger.
+ CustomFramesContainer._py_db_command_thread_event = Null()
+
+#Initialize it the first time (it may be reinitialized later on when dealing with a fork).
+CustomFramesContainerInit()
+
+
+#=======================================================================================================================
+# CustomFrame
+#=======================================================================================================================
+class CustomFrame:
+
+ def __init__(self, name, frame, thread_id):
+ # 0 = string with the representation of that frame
+ self.name = name
+
+ # 1 = the frame to show
+ self.frame = frame
+
+ # 2 = an integer identifying the last time the frame was changed.
+ self.mod_time = 0
+
+ # 3 = the thread id of the given frame
+ self.thread_id = thread_id
+
+
+def addCustomFrame(frame, name, thread_id):
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ curr_thread_id = GetThreadId(threadingCurrentThread())
+ next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1
+
+ # Note: the frame id kept contains an id and thread information on the thread where the frame was added
+ # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id).
+ frame_id = '__frame__:%s|%s' % (next_id, curr_thread_id)
+ if DEBUG:
+ sys.stderr.write('addCustomFrame: %s (%s) %s %s\n' % (
+ frame_id, GetFilenameAndBase(frame)[1], frame.f_lineno, frame.f_code.co_name))
+
+ CustomFramesContainer.custom_frames[frame_id] = CustomFrame(name, frame, thread_id)
+ CustomFramesContainer._py_db_command_thread_event.set()
+ return frame_id
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
+
+
+def updateCustomFrame(frame_id, frame, thread_id, name=None):
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ if DEBUG:
+ sys.stderr.write('updateCustomFrame: %s\n' % frame_id)
+ try:
+ old = CustomFramesContainer.custom_frames[frame_id]
+ if name is not None:
+ old.name = name
+ old.mod_time += 1
+ old.thread_id = thread_id
+ except:
+ sys.stderr.write('Unable to get frame to replace: %s\n' % (frame_id,))
+ import traceback;traceback.print_exc()
+
+ CustomFramesContainer._py_db_command_thread_event.set()
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
+
+
+def getCustomFrame(thread_id, frame_id):
+ '''
+ :param thread_id: This should actually be the frame_id which is returned by addCustomFrame.
+ :param frame_id: This is the actual id() of the frame
+ '''
+
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ frame_id = int(frame_id)
+ f = CustomFramesContainer.custom_frames[thread_id].frame
+ while f is not None:
+ if id(f) == frame_id:
+ return f
+ f = f.f_back
+ finally:
+ f = None
+ CustomFramesContainer.custom_frames_lock.release()
+
+
+def removeCustomFrame(frame_id):
+ CustomFramesContainer.custom_frames_lock.acquire()
+ try:
+ if DEBUG:
+ sys.stderr.write('removeCustomFrame: %s\n' % frame_id)
+ DictPop(CustomFramesContainer.custom_frames, frame_id, None)
+ CustomFramesContainer._py_db_command_thread_event.set()
+ finally:
+ CustomFramesContainer.custom_frames_lock.release()
diff --git a/python/helpers/pydev/pydevd_exec.py b/python/helpers/pydev/pydevd_exec.py
index 6cffeaf86e27..9a342ee1b015 100644
--- a/python/helpers/pydev/pydevd_exec.py
+++ b/python/helpers/pydev/pydevd_exec.py
@@ -1,2 +1,5 @@
-def Exec(exp, global_vars, local_vars):
- exec exp in global_vars, local_vars \ No newline at end of file
+def Exec(exp, global_vars, local_vars=None):
+ if local_vars is not None:
+ exec exp in global_vars, local_vars
+ else:
+ exec exp in global_vars \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_exec2.py b/python/helpers/pydev/pydevd_exec2.py
index 9b234b76344d..ee4f37a6c792 100644
--- a/python/helpers/pydev/pydevd_exec2.py
+++ b/python/helpers/pydev/pydevd_exec2.py
@@ -1,2 +1,5 @@
-def Exec(exp, global_vars, local_vars):
- exec(exp, global_vars, local_vars) \ No newline at end of file
+def Exec(exp, global_vars, local_vars=None):
+ if local_vars is not None:
+ exec(exp, global_vars, local_vars)
+ else:
+ exec(exp, global_vars) \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py
index a91f16060211..05faaeb77ff2 100644
--- a/python/helpers/pydev/pydevd_frame.py
+++ b/python/helpers/pydev/pydevd_frame.py
@@ -210,6 +210,7 @@ class PyDBFrame:
return self.trace_dispatch
except:
+ traceback.print_exc()
raise
#step handling. We stop when we hit the right frame
@@ -339,45 +340,46 @@ class PyDBFrame:
pass #ok, psyco not available
def shouldStopOnDjangoBreak(self, frame, event, arg):
- mainDebugger, filename, info, thread = self._args
- flag = False
- filename = get_template_file_name(frame)
- pydev_log.debug("Django is rendering a template: %s\n" % filename)
- django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename)
- if django_breakpoints_for_file:
- pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
- template_line = get_template_line(frame)
- pydev_log.debug("Tracing template line: %d\n" % template_line)
-
- if DictContains(django_breakpoints_for_file, template_line):
- django_breakpoint = django_breakpoints_for_file[template_line]
-
- if django_breakpoint.is_triggered(frame):
- pydev_log.debug("Breakpoint is triggered.\n")
- flag = True
- new_frame = DjangoTemplateFrame(frame)
-
- if django_breakpoint.condition is not None:
- try:
- val = eval(django_breakpoint.condition, new_frame.f_globals, new_frame.f_locals)
- if not val:
- flag = False
- pydev_log.debug("Condition '%s' is evaluated to %s. Not suspending.\n" %(django_breakpoint.condition, val))
- except:
- pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1]))
-
- if django_breakpoint.expression is not None:
- try:
- try:
- val = eval(django_breakpoint.expression, new_frame.f_globals, new_frame.f_locals)
- except:
- val = sys.exc_info()[1]
- finally:
- if val is not None:
- thread.additionalInfo.message = val
- if flag:
- frame = suspend_django(self, mainDebugger, thread, frame)
- return (flag, frame)
+ mainDebugger, filename, info, thread = self._args
+ flag = False
+ filename = get_template_file_name(frame)
+ pydev_log.debug("Django is rendering a template: %s\n" % filename)
+ django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename)
+ if django_breakpoints_for_file:
+ pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
+ template_line = get_template_line(frame)
+ pydev_log.debug("Tracing template line: %d\n" % template_line)
+
+ if DictContains(django_breakpoints_for_file, template_line):
+ django_breakpoint = django_breakpoints_for_file[template_line]
+
+ if django_breakpoint.is_triggered(frame):
+ pydev_log.debug("Breakpoint is triggered.\n")
+ flag = True
+ new_frame = DjangoTemplateFrame(frame)
+
+ if django_breakpoint.condition is not None:
+ try:
+ val = eval(django_breakpoint.condition, new_frame.f_globals, new_frame.f_locals)
+ if not val:
+ flag = False
+ pydev_log.debug("Condition '%s' is evaluated to %s. Not suspending.\n" % (django_breakpoint.condition, val))
+ except:
+ pydev_log.info(
+ 'Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1]))
+
+ if django_breakpoint.expression is not None:
+ try:
+ try:
+ val = eval(django_breakpoint.expression, new_frame.f_globals, new_frame.f_locals)
+ except:
+ val = sys.exc_info()[1]
+ finally:
+ if val is not None:
+ thread.additionalInfo.message = val
+ if flag:
+ frame = suspend_django(self, mainDebugger, thread, frame)
+ return (flag, frame)
def add_exception_to_frame(frame, exception_info):
frame.f_locals['__exception__'] = exception_info \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_import_class.py b/python/helpers/pydev/pydevd_import_class.py
index c84b0cee3b61..3c3bec848abd 100644
--- a/python/helpers/pydev/pydevd_import_class.py
+++ b/python/helpers/pydev/pydevd_import_class.py
@@ -1,4 +1,4 @@
-#Note: code gotten from importsTipper.
+#Note: code gotten from _pydev_imports_tipper.
import sys
diff --git a/python/helpers/pydev/pydevd_io.py b/python/helpers/pydev/pydevd_io.py
index ca8c49308daa..a83adc8de2b9 100644
--- a/python/helpers/pydev/pydevd_io.py
+++ b/python/helpers/pydev/pydevd_io.py
@@ -1,10 +1,14 @@
+import pydevd_constants #@UnusedImport -- defines False and True if not there.
+
+IS_PY3K = pydevd_constants.IS_PY3K
+
class IORedirector:
'''This class works to redirect the write function to many streams
'''
-
+
def __init__(self, *args):
self._redirectTo = args
-
+
def write(self, s):
for r in self._redirectTo:
try:
@@ -13,7 +17,7 @@ class IORedirector:
pass
def isatty(self):
- return False #not really a file
+ return False
def flush(self):
for r in self._redirectTo:
@@ -33,17 +37,22 @@ class IOBuf:
'''
def __init__(self):
self.buflist = []
-
+ import os
+ self.encoding = os.environ.get('PYTHONIOENCODING', 'utf-8')
+
def getvalue(self):
b = self.buflist
self.buflist = [] #clear it
return ''.join(b)
def write(self, s):
+ if not IS_PY3K:
+ if isinstance(s, unicode):
+ s = s.encode(self.encoding)
self.buflist.append(s)
def isatty(self):
- return False #not really a file
+ return False
def flush(self):
pass
@@ -88,4 +97,3 @@ def EndRedirect(std='stdout'):
stack = getattr(_RedirectionsHolder, '_stack_%s' % std)
setattr(sys, std, stack.pop())
-
diff --git a/python/helpers/pydev/pydevd_reload.py b/python/helpers/pydev/pydevd_reload.py
index 03ca2fdc74ba..1533c8958a88 100644
--- a/python/helpers/pydev/pydevd_reload.py
+++ b/python/helpers/pydev/pydevd_reload.py
@@ -1,208 +1,453 @@
"""
-Copied from the python xreload (available for change)
+Based on the python xreload.
+
+Changes
+======================
+
+1. we don't recreate the old namespace from new classes. Rather, we keep the existing namespace,
+load a new version of it and update only some of the things we can inplace. That way, we don't break
+things such as singletons or end up with a second representation of the same class in memory.
+
+2. If we find it to be a __metaclass__, we try to update it as a regular class.
+
+3. We don't remove old attributes (and leave them lying around even if they're no longer used).
+
+4. Reload hooks were changed
+
+These changes make it more stable, especially in the common case (where in a debug session only the
+contents of a function are changed), besides providing flexibility for users that want to extend
+on it.
+
+
+
+Hooks
+======================
+
+Classes/modules can be specially crafted to work with the reload (so that it can, for instance,
+update some constant which was changed).
+
+1. To participate in the change of some attribute:
+
+ In a module:
+
+ __xreload_old_new__(namespace, name, old, new)
+
+ in a class:
+
+ @classmethod
+ __xreload_old_new__(cls, name, old, new)
+
+ A class or module may include a method called '__xreload_old_new__' which is called when we're
+ unable to reload a given attribute.
+
+
+
+2. To do something after the whole reload is finished:
+
+ In a module:
+
+ __xreload_after_reload_update__(namespace):
+
+ In a class:
+
+ @classmethod
+ __xreload_after_reload_update__(cls):
-Alternative to reload().
-This works by executing the module in a scratch namespace, and then
-patching classes, methods and functions in place. This avoids the
-need to patch instances. New objects are copied into the target
-namespace.
+ A class or module may include a method called '__xreload_after_reload_update__' which is called
+ after the reload finishes.
-Some of the many limitations include:
-- Global mutable objects other than classes are simply replaced, not patched
+Important: when providing a hook, always use the namespace or cls provided and not anything in the global
+namespace, as the global namespace are only temporarily created during the reload and may not reflect the
+actual application state (while the cls and namespace passed are).
-- Code using metaclasses is not handled correctly
-- Code creating global singletons is not handled correctly
+Current limitations
+======================
-- Functions and methods using decorators (other than classmethod and
- staticmethod) is not handled correctly
-- Renamings are not handled correctly
+- Attributes/constants are added, but not changed (so singletons and the application state is not
+ broken -- use provided hooks to workaround it).
-- Dependent modules are not reloaded
+- Code using metaclasses may not always work.
-- When a dependent module contains 'from foo import bar', and
- reloading foo deletes foo.bar, the dependent module continues to use
- the old foo.bar object rather than failing
+- Functions and methods using decorators (other than classmethod and staticmethod) are not handled
+ correctly.
-- Frozen modules and modules loaded from zip files aren't handled
- correctly
+- Renamings are not handled correctly.
+
+- Dependent modules are not reloaded.
+
+- New __slots__ can't be added to existing classes.
+
+
+Info
+======================
+
+Original: http://svn.python.org/projects/sandbox/trunk/xreload/xreload.py
+Note: it seems https://github.com/plone/plone.reload/blob/master/plone/reload/xreload.py enhances it (to check later)
+
+Interesting alternative: https://code.google.com/p/reimport/
+
+Alternative to reload().
+
+This works by executing the module in a scratch namespace, and then patching classes, methods and
+functions in place. This avoids the need to patch instances. New objects are copied into the
+target namespace.
-- Classes involving __slots__ are not handled correctly
"""
import imp
+from pydev_imports import Exec
+import pydevd_dont_trace
import sys
+import traceback
import types
+NO_DEBUG = 0
+LEVEL1 = 1
+LEVEL2 = 2
+
+DEBUG = NO_DEBUG
+
+def write(*args):
+ new_lst = []
+ for a in args:
+ new_lst.append(str(a))
+
+ msg = ' '.join(new_lst)
+ sys.stdout.write('%s\n' % (msg,))
+def write_err(*args):
+ new_lst = []
+ for a in args:
+ new_lst.append(str(a))
+
+ msg = ' '.join(new_lst)
+ sys.stderr.write('pydev debugger: %s\n' % (msg,))
+
+def notify_info0(*args):
+ write_err(*args)
+
+def notify_info(*args):
+ if DEBUG >= LEVEL1:
+ write(*args)
+
+def notify_info2(*args):
+ if DEBUG >= LEVEL2:
+ write(*args)
+
+def notify_error(*args):
+ write_err(*args)
+
+
+
+#=======================================================================================================================
+# code_objects_equal
+#=======================================================================================================================
+def code_objects_equal(code0, code1):
+ for d in dir(code0):
+ if d.startswith('_') or 'lineno' in d:
+ continue
+ if getattr(code0, d) != getattr(code1, d):
+ return False
+ return True
+
+
+#=======================================================================================================================
+# xreload
+#=======================================================================================================================
def xreload(mod):
"""Reload a module in place, updating classes, methods and functions.
- Args:
- mod: a module object
+ mod: a module object
- Returns:
- The (updated) input object itself.
- """
- # Get the module name, e.g. 'foo.bar.whatever'
- modname = mod.__name__
- # Get the module namespace (dict) early; this is part of the type check
- modns = mod.__dict__
- # Parse it into package name and module name, e.g. 'foo.bar' and 'whatever'
- i = modname.rfind(".")
- if i >= 0:
- pkgname, modname = modname[:i], modname[i+1:]
- else:
- pkgname = None
- # Compute the search path
- if pkgname:
- # We're not reloading the package, only the module in it
- pkg = sys.modules[pkgname]
- path = pkg.__path__ # Search inside the package
- else:
- # Search the top-level module path
- pkg = None
- path = None # Make find_module() uses the default search path
- # Find the module; may raise ImportError
- (stream, filename, (suffix, mode, kind)) = imp.find_module(modname, path)
- # Turn it into a code object
- try:
- # Is it Python source code or byte code read from a file?
- if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
- # Fall back to built-in reload()
- return reload(mod)
- if kind == imp.PY_SOURCE:
- source = stream.read()
- code = compile(source, filename, "exec")
- else:
- import marshal
- code = marshal.load(stream)
- finally:
- if stream:
- stream.close()
- # Execute the code. We copy the module dict to a temporary; then
- # clear the module dict; then execute the new code in the module
- # dict; then swap things back and around. This trick (due to
- # Glyph Lefkowitz) ensures that the (readonly) __globals__
- # attribute of methods and functions is set to the correct dict
- # object.
- tmpns = modns.copy()
- modns.clear()
- modns["__name__"] = tmpns["__name__"]
- exec(code, modns)
- # Now we get to the hard part
- oldnames = set(tmpns)
- newnames = set(modns)
- # Update attributes in place
- for name in oldnames & newnames:
- modns[name] = _update(tmpns[name], modns[name])
- # Done!
- return mod
-
-
-def _update(oldobj, newobj):
- """Update oldobj, if possible in place, with newobj.
-
- If oldobj is immutable, this simply returns newobj.
-
- Args:
- oldobj: the object to be updated
- newobj: the object used as the source for the update
-
- Returns:
- either oldobj, updated in place, or newobj.
+ Returns a boolean indicating whether a change was done.
"""
- if oldobj is newobj:
- # Probably something imported
- return newobj
- if type(oldobj) is not type(newobj):
- # Cop-out: if the type changed, give up
- return newobj
- if hasattr(newobj, "__reload_update__"):
- # Provide a hook for updating
- return newobj.__reload_update__(oldobj)
-
- if hasattr(types, 'ClassType'):
- classtype = types.ClassType
- else:
- classtype = type
-
- if isinstance(newobj, classtype):
- return _update_class(oldobj, newobj)
- if isinstance(newobj, types.FunctionType):
- return _update_function(oldobj, newobj)
- if isinstance(newobj, types.MethodType):
- return _update_method(oldobj, newobj)
- if isinstance(newobj, classmethod):
- return _update_classmethod(oldobj, newobj)
- if isinstance(newobj, staticmethod):
- return _update_staticmethod(oldobj, newobj)
- # Not something we recognize, just give up
- return newobj
-
-
-# All of the following functions have the same signature as _update()
-
-
-def _update_function(oldfunc, newfunc):
- """Update a function object."""
- oldfunc.__doc__ = newfunc.__doc__
- oldfunc.__dict__.update(newfunc.__dict__)
-
- try:
- oldfunc.__code__ = newfunc.__code__
- except AttributeError:
- oldfunc.func_code = newfunc.func_code
- try:
- oldfunc.__defaults__ = newfunc.__defaults__
- except AttributeError:
- oldfunc.func_defaults = newfunc.func_defaults
-
- return oldfunc
-
-
-def _update_method(oldmeth, newmeth):
- """Update a method object."""
- # XXX What if im_func is not a function?
- _update(oldmeth.im_func, newmeth.im_func)
- return oldmeth
-
-
-def _update_class(oldclass, newclass):
- """Update a class object."""
- olddict = oldclass.__dict__
- newdict = newclass.__dict__
- oldnames = set(olddict)
- newnames = set(newdict)
- for name in newnames - oldnames:
- setattr(oldclass, name, newdict[name])
- for name in oldnames - newnames:
- delattr(oldclass, name)
- for name in oldnames & newnames - set(['__dict__', '__doc__']):
- setattr(oldclass, name, _update(olddict[name], newdict[name]))
- return oldclass
-
-
-def _update_classmethod(oldcm, newcm):
- """Update a classmethod update."""
- # While we can't modify the classmethod object itself (it has no
- # mutable attributes), we *can* extract the underlying function
- # (by calling __get__(), which returns a method object) and update
- # it in-place. We don't have the class available to pass to
- # __get__() but any object except None will do.
- _update(oldcm.__get__(0), newcm.__get__(0))
- return newcm
-
-
-def _update_staticmethod(oldsm, newsm):
- """Update a staticmethod update."""
- # While we can't modify the staticmethod object itself (it has no
- # mutable attributes), we *can* extract the underlying function
- # (by calling __get__(), which returns it) and update it in-place.
- # We don't have the class available to pass to __get__() but any
- # object except None will do.
- _update(oldsm.__get__(0), newsm.__get__(0))
- return newsm
+ r = Reload(mod)
+ r.apply()
+ found_change = r.found_change
+ r = None
+ pydevd_dont_trace.clear_trace_filter_cache()
+ return found_change
+
+
+# This isn't actually used... Initially I planned to reload variables which are immutable on the
+# namespace, but this can destroy places where we're saving state, which may not be what we want,
+# so, we're being conservative and giving the user hooks if he wants to do a reload.
+#
+# immutable_types = [int, str, float, tuple] #That should be common to all Python versions
+#
+# for name in 'long basestr unicode frozenset'.split():
+# try:
+# immutable_types.append(__builtins__[name])
+# except:
+# pass #Just ignore: not all python versions are created equal.
+# immutable_types = tuple(immutable_types)
+
+
+#=======================================================================================================================
+# Reload
+#=======================================================================================================================
+class Reload:
+
+ def __init__(self, mod):
+ self.mod = mod
+ self.found_change = False
+
+ def apply(self):
+ mod = self.mod
+ self._on_finish_callbacks = []
+ try:
+ # Get the module name, e.g. 'foo.bar.whatever'
+ modname = mod.__name__
+ # Get the module namespace (dict) early; this is part of the type check
+ modns = mod.__dict__
+ # Parse it into package name and module name, e.g. 'foo.bar' and 'whatever'
+ i = modname.rfind(".")
+ if i >= 0:
+ pkgname, modname = modname[:i], modname[i + 1:]
+ else:
+ pkgname = None
+ # Compute the search path
+ if pkgname:
+ # We're not reloading the package, only the module in it
+ pkg = sys.modules[pkgname]
+ path = pkg.__path__ # Search inside the package
+ else:
+ # Search the top-level module path
+ pkg = None
+ path = None # Make find_module() uses the default search path
+ # Find the module; may raise ImportError
+ (stream, filename, (suffix, mode, kind)) = imp.find_module(modname, path)
+ # Turn it into a code object
+ try:
+ # Is it Python source code or byte code read from a file?
+ if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
+ # Fall back to built-in reload()
+ notify_error('Could not find source to reload (mod: %s)' % (modname,))
+ return
+ if kind == imp.PY_SOURCE:
+ source = stream.read()
+ code = compile(source, filename, "exec")
+ else:
+ import marshal
+ code = marshal.load(stream)
+ finally:
+ if stream:
+ stream.close()
+ # Execute the code. We copy the module dict to a temporary; then
+ # clear the module dict; then execute the new code in the module
+ # dict; then swap things back and around. This trick (due to
+ # Glyph Lefkowitz) ensures that the (readonly) __globals__
+ # attribute of methods and functions is set to the correct dict
+ # object.
+ new_namespace = modns.copy()
+ new_namespace.clear()
+ new_namespace["__name__"] = modns["__name__"]
+ Exec(code, new_namespace)
+ # Now we get to the hard part
+ oldnames = set(modns)
+ newnames = set(new_namespace)
+
+ # Create new tokens (note: not deleting existing)
+ for name in newnames - oldnames:
+ notify_info0('Added:', name, 'to namespace')
+ self.found_change = True
+ modns[name] = new_namespace[name]
+
+ # Update in-place what we can
+ for name in oldnames & newnames:
+ self._update(modns, name, modns[name], new_namespace[name])
+
+ self._handle_namespace(modns)
+
+ for c in self._on_finish_callbacks:
+ c()
+ del self._on_finish_callbacks[:]
+ except:
+ traceback.print_exc()
+
+
+ def _handle_namespace(self, namespace, is_class_namespace=False):
+ on_finish = None
+ if is_class_namespace:
+ xreload_after_update = getattr(namespace, '__xreload_after_reload_update__', None)
+ if xreload_after_update is not None:
+ self.found_change = True
+ on_finish = lambda: xreload_after_update()
+
+ elif '__xreload_after_reload_update__' in namespace:
+ xreload_after_update = namespace['__xreload_after_reload_update__']
+ self.found_change = True
+ on_finish = lambda: xreload_after_update(namespace)
+
+
+ if on_finish is not None:
+ # If a client wants to know about it, give him a chance.
+ self._on_finish_callbacks.append(on_finish)
+
+
+
+ def _update(self, namespace, name, oldobj, newobj, is_class_namespace=False):
+ """Update oldobj, if possible in place, with newobj.
+
+ If oldobj is immutable, this simply returns newobj.
+
+ Args:
+ oldobj: the object to be updated
+ newobj: the object used as the source for the update
+ """
+ try:
+ notify_info2('Updating: ', oldobj)
+ if oldobj is newobj:
+ # Probably something imported
+ return
+
+ if type(oldobj) is not type(newobj):
+ # Cop-out: if the type changed, give up
+ notify_error('Type of: %s changed... Skipping.' % (oldobj,))
+ return
+
+ if isinstance(newobj, types.FunctionType):
+ self._update_function(oldobj, newobj)
+ return
+
+ if isinstance(newobj, types.MethodType):
+ self._update_method(oldobj, newobj)
+ return
+
+ if isinstance(newobj, classmethod):
+ self._update_classmethod(oldobj, newobj)
+ return
+
+ if isinstance(newobj, staticmethod):
+ self._update_staticmethod(oldobj, newobj)
+ return
+
+ if hasattr(types, 'ClassType'):
+ classtype = (types.ClassType, type) #object is not instance of types.ClassType.
+ else:
+ classtype = type
+
+ if isinstance(newobj, classtype):
+ self._update_class(oldobj, newobj)
+ return
+
+ # New: dealing with metaclasses.
+ if hasattr(newobj, '__metaclass__') and hasattr(newobj, '__class__') and newobj.__metaclass__ == newobj.__class__:
+ self._update_class(oldobj, newobj)
+ return
+
+ if namespace is not None:
+
+ if oldobj != newobj and str(oldobj) != str(newobj) and repr(oldobj) != repr(newobj):
+ xreload_old_new = None
+ if is_class_namespace:
+ xreload_old_new = getattr(namespace, '__xreload_old_new__', None)
+ if xreload_old_new is not None:
+ self.found_change = True
+ xreload_old_new(name, oldobj, newobj)
+
+ elif '__xreload_old_new__' in namespace:
+ xreload_old_new = namespace['__xreload_old_new__']
+ xreload_old_new(namespace, name, oldobj, newobj)
+ self.found_change = True
+
+ # Too much information to the user...
+ # else:
+ # notify_info0('%s NOT updated. Create __xreload_old_new__(name, old, new) for custom reload' % (name,))
+
+ except:
+ notify_error('Exception found when updating %s. Proceeding for other items.' % (name,))
+ traceback.print_exc()
+
+
+ # All of the following functions have the same signature as _update()
+
+
+ def _update_function(self, oldfunc, newfunc):
+ """Update a function object."""
+ oldfunc.__doc__ = newfunc.__doc__
+ oldfunc.__dict__.update(newfunc.__dict__)
+
+ try:
+ newfunc.__code__
+ attr_name = '__code__'
+ except AttributeError:
+ newfunc.func_code
+ attr_name = 'func_code'
+
+ old_code = getattr(oldfunc, attr_name)
+ new_code = getattr(newfunc, attr_name)
+ if not code_objects_equal(old_code, new_code):
+ notify_info0('Updated function code:', oldfunc)
+ setattr(oldfunc, attr_name, new_code)
+ self.found_change = True
+
+ try:
+ oldfunc.__defaults__ = newfunc.__defaults__
+ except AttributeError:
+ oldfunc.func_defaults = newfunc.func_defaults
+
+ return oldfunc
+
+
+ def _update_method(self, oldmeth, newmeth):
+ """Update a method object."""
+ # XXX What if im_func is not a function?
+ if hasattr(oldmeth, 'im_func') and hasattr(newmeth, 'im_func'):
+ self._update(None, None, oldmeth.im_func, newmeth.im_func)
+ elif hasattr(oldmeth, '__func__') and hasattr(newmeth, '__func__'):
+ self._update(None, None, oldmeth.__func__, newmeth.__func__)
+ return oldmeth
+
+
+ def _update_class(self, oldclass, newclass):
+ """Update a class object."""
+ olddict = oldclass.__dict__
+ newdict = newclass.__dict__
+
+ oldnames = set(olddict)
+ newnames = set(newdict)
+
+ for name in newnames - oldnames:
+ setattr(oldclass, name, newdict[name])
+ notify_info0('Added:', name, 'to', oldclass)
+ self.found_change = True
+
+ # Note: not removing old things...
+ # for name in oldnames - newnames:
+ # notify_info('Removed:', name, 'from', oldclass)
+ # delattr(oldclass, name)
+
+ for name in (oldnames & newnames) - set(['__dict__', '__doc__']):
+ self._update(oldclass, name, olddict[name], newdict[name], is_class_namespace=True)
+
+ old_bases = getattr(oldclass, '__bases__', None)
+ new_bases = getattr(newclass, '__bases__', None)
+ if str(old_bases) != str(new_bases):
+ notify_error('Changing the hierarchy of a class is not supported. %s may be inconsistent.' % (oldclass,))
+
+ self._handle_namespace(oldclass, is_class_namespace=True)
+
+
+ def _update_classmethod(self, oldcm, newcm):
+ """Update a classmethod update."""
+ # While we can't modify the classmethod object itself (it has no
+ # mutable attributes), we *can* extract the underlying function
+ # (by calling __get__(), which returns a method object) and update
+ # it in-place. We don't have the class available to pass to
+ # __get__() but any object except None will do.
+ self._update(None, None, oldcm.__get__(0), newcm.__get__(0))
+
+
+ def _update_staticmethod(self, oldsm, newsm):
+ """Update a staticmethod update."""
+ # While we can't modify the staticmethod object itself (it has no
+ # mutable attributes), we *can* extract the underlying function
+ # (by calling __get__(), which returns it) and update it in-place.
+ # We don't have the class available to pass to __get__() but any
+ # object except None will do.
+ self._update(None, None, oldsm.__get__(0), newsm.__get__(0))
diff --git a/python/helpers/pydev/pydevd_resolver.py b/python/helpers/pydev/pydevd_resolver.py
index 114b8494b654..614549f74f37 100644
--- a/python/helpers/pydev/pydevd_resolver.py
+++ b/python/helpers/pydev/pydevd_resolver.py
@@ -3,6 +3,7 @@ try:
except:
import io as StringIO
import traceback
+from os.path import basename
try:
__setFalse = False
@@ -357,9 +358,100 @@ class JyArrayResolver:
ret['__len__'] = len(obj)
return ret
+
+#=======================================================================================================================
+# NdArrayResolver
+#=======================================================================================================================
+class NdArrayResolver:
+ '''
+ This resolves a numpy ndarray returning some metadata about the NDArray
+ '''
+
+ def resolve(self, obj, attribute):
+ if attribute == '__internals__':
+ return defaultResolver.getDictionary(obj)
+ if attribute == 'min':
+ return obj.min()
+ if attribute == 'max':
+ return obj.max()
+ if attribute == 'shape':
+ return obj.shape
+ if attribute == 'dtype':
+ return obj.dtype
+ if attribute == 'size':
+ return obj.size
+ return None
+
+ def getDictionary(self, obj):
+ ret = dict()
+ ret['__internals__'] = defaultResolver.getDictionary(obj)
+ if obj.size > 1024 * 1024:
+ ret['min'] = 'ndarray too big, calculating min would slow down debugging'
+ ret['max'] = 'ndarray too big, calculating max would slow down debugging'
+ else:
+ ret['min'] = obj.min()
+ ret['max'] = obj.max()
+ ret['shape'] = obj.shape
+ ret['dtype'] = obj.dtype
+ ret['size'] = obj.size
+ return ret
+
+
+#=======================================================================================================================
+# FrameResolver
+#=======================================================================================================================
+class FrameResolver:
+ '''
+ This resolves a frame.
+ '''
+
+ def resolve(self, obj, attribute):
+ if attribute == '__internals__':
+ return defaultResolver.getDictionary(obj)
+
+ if attribute == 'stack':
+ return self.getFrameStack(obj)
+
+ if attribute == 'f_locals':
+ return obj.f_locals
+
+ return None
+
+
+ def getDictionary(self, obj):
+ ret = dict()
+ ret['__internals__'] = defaultResolver.getDictionary(obj)
+ ret['stack'] = self.getFrameStack(obj)
+ ret['f_locals'] = obj.f_locals
+ return ret
+
+
+ def getFrameStack(self, frame):
+ ret = []
+ if frame is not None:
+ ret.append(self.getFrameName(frame))
+
+ while frame.f_back:
+ frame = frame.f_back
+ ret.append(self.getFrameName(frame))
+
+ return ret
+
+ def getFrameName(self, frame):
+ if frame is None:
+ return 'None'
+ try:
+ name = basename(frame.f_code.co_filename)
+ return 'frame: %s [%s:%s] id:%s' % (frame.f_code.co_name, name, frame.f_lineno, id(frame))
+ except:
+ return 'frame object'
+
+
defaultResolver = DefaultResolver()
dictResolver = DictResolver()
tupleResolver = TupleResolver()
instanceResolver = InstanceResolver()
jyArrayResolver = JyArrayResolver()
setResolver = SetResolver()
+ndarrayResolver = NdArrayResolver()
+frameResolver = FrameResolver()
diff --git a/python/helpers/pydev/pydevd_save_locals.py b/python/helpers/pydev/pydevd_save_locals.py
new file mode 100644
index 000000000000..2808081a5866
--- /dev/null
+++ b/python/helpers/pydev/pydevd_save_locals.py
@@ -0,0 +1,58 @@
+"""
+Utility for saving locals.
+"""
+import sys
+
+def is_save_locals_available():
+ try:
+ if '__pypy__' in sys.builtin_module_names:
+ import __pypy__
+ save_locals = __pypy__.locals_to_fast
+ return True
+ except:
+ pass
+
+
+ try:
+ import ctypes
+ except:
+ return False #Not all Python versions have it
+
+ try:
+ func = ctypes.pythonapi.PyFrame_LocalsToFast
+ except:
+ return False
+
+ return True
+
+def save_locals(frame):
+ """
+ Copy values from locals_dict into the fast stack slots in the given frame.
+
+ Note: the 'save_locals' branch had a different approach wrapping the frame (much more code, but it gives ideas
+ on how to save things partially, not the 'whole' locals).
+ """
+ try:
+ if '__pypy__' in sys.builtin_module_names:
+ import __pypy__
+ save_locals = __pypy__.locals_to_fast
+ save_locals(frame)
+ return
+ except:
+ pass
+
+
+ try:
+ import ctypes
+ except:
+ return #Not all Python versions have it
+
+ try:
+ func = ctypes.pythonapi.PyFrame_LocalsToFast
+ except:
+ return
+
+ #parameter 0: don't set to null things that are not in the frame.f_locals (which seems good in the debugger context).
+ func(ctypes.py_object(frame), ctypes.c_int(0))
+
+
diff --git a/python/helpers/pydev/pydevd_stackless.py b/python/helpers/pydev/pydevd_stackless.py
new file mode 100644
index 000000000000..bd3b306dad63
--- /dev/null
+++ b/python/helpers/pydev/pydevd_stackless.py
@@ -0,0 +1,412 @@
+from __future__ import nested_scopes
+from pydevd_constants import * # @UnusedWildImport
+import stackless # @UnresolvedImport
+from pydevd_tracing import SetTrace
+from pydevd_custom_frames import updateCustomFrame, removeCustomFrame, addCustomFrame
+from pydevd_comm import GetGlobalDebugger
+import weakref
+from pydevd_file_utils import GetFilenameAndBase
+from pydevd import DONT_TRACE
+
+
+# Used so that we don't loose the id (because we'll remove when it's not alive and would generate a new id for the
+# same tasklet).
+class TaskletToLastId:
+ '''
+ So, why not a WeakKeyDictionary?
+ The problem is that removals from the WeakKeyDictionary will create a new tasklet (as it adds a callback to
+ remove the key when it's garbage-collected), so, we can get into a recursion.
+ '''
+
+ def __init__(self):
+ self.tasklet_ref_to_last_id = {}
+ self._i = 0
+
+
+ def get(self, tasklet):
+ return self.tasklet_ref_to_last_id.get(weakref.ref(tasklet))
+
+
+ def __setitem__(self, tasklet, last_id):
+ self.tasklet_ref_to_last_id[weakref.ref(tasklet)] = last_id
+ self._i += 1
+ if self._i % 100 == 0: #Collect at each 100 additions to the dict (no need to rush).
+ for tasklet_ref in list(self.tasklet_ref_to_last_id.keys()):
+ if tasklet_ref() is None:
+ del self.tasklet_ref_to_last_id[tasklet_ref]
+
+
+_tasklet_to_last_id = TaskletToLastId()
+
+#=======================================================================================================================
+# _TaskletInfo
+#=======================================================================================================================
+class _TaskletInfo:
+
+ _last_id = 0
+
+ def __init__(self, tasklet_weakref, tasklet):
+ self.frame_id = None
+ self.tasklet_weakref = tasklet_weakref
+
+ last_id = _tasklet_to_last_id.get(tasklet)
+ if last_id is None:
+ _TaskletInfo._last_id += 1
+ last_id = _TaskletInfo._last_id
+ _tasklet_to_last_id[tasklet] = last_id
+
+ self._tasklet_id = last_id
+
+ self.update_name()
+
+ def update_name(self):
+ tasklet = self.tasklet_weakref()
+ if tasklet:
+ if tasklet.blocked:
+ state = 'blocked'
+ elif tasklet.paused:
+ state = 'paused'
+ elif tasklet.scheduled:
+ state = 'scheduled'
+ else:
+ state = '<UNEXPECTED>'
+
+ try:
+ name = tasklet.name
+ except AttributeError:
+ if tasklet.is_main:
+ name = 'MainTasklet'
+ else:
+ name = 'Tasklet-%s' % (self._tasklet_id,)
+
+ thread_id = tasklet.thread_id
+ if thread_id != -1:
+ for thread in threading.enumerate():
+ if thread.ident == thread_id:
+ if thread.name:
+ thread_name = "of %s" % (thread.name,)
+ else:
+ thread_name = "of Thread-%s" % (thread.name or str(thread_id),)
+ break
+ else:
+ # should not happen.
+ thread_name = "of Thread-%s" % (str(thread_id),)
+ thread = None
+ else:
+ # tasklet is no longer bound to a thread, because its thread ended
+ thread_name = "without thread"
+
+ tid = id(tasklet)
+ tasklet = None
+ else:
+ state = 'dead'
+ name = 'Tasklet-%s' % (self._tasklet_id,)
+ thread_name = ""
+ tid = '-'
+ self.tasklet_name = '%s %s %s (%s)' % (state, name, thread_name, tid)
+
+ if not hasattr(stackless.tasklet, "trace_function"):
+ # bug https://bitbucket.org/stackless-dev/stackless/issue/42
+ # is not fixed. Stackless releases before 2014
+ def update_name(self):
+ tasklet = self.tasklet_weakref()
+ if tasklet:
+ try:
+ name = tasklet.name
+ except AttributeError:
+ if tasklet.is_main:
+ name = 'MainTasklet'
+ else:
+ name = 'Tasklet-%s' % (self._tasklet_id,)
+
+ thread_id = tasklet.thread_id
+ for thread in threading.enumerate():
+ if thread.ident == thread_id:
+ if thread.name:
+ thread_name = "of %s" % (thread.name,)
+ else:
+ thread_name = "of Thread-%s" % (thread.name or str(thread_id),)
+ break
+ else:
+ # should not happen.
+ thread_name = "of Thread-%s" % (str(thread_id),)
+ thread = None
+
+ tid = id(tasklet)
+ tasklet = None
+ else:
+ name = 'Tasklet-%s' % (self._tasklet_id,)
+ thread_name = ""
+ tid = '-'
+ self.tasklet_name = '%s %s (%s)' % (name, thread_name, tid)
+
+_weak_tasklet_registered_to_info = {}
+
+#=======================================================================================================================
+# get_tasklet_info
+#=======================================================================================================================
+def get_tasklet_info(tasklet):
+ return register_tasklet_info(tasklet)
+
+
+#=======================================================================================================================
+# register_tasklet_info
+#=======================================================================================================================
+def register_tasklet_info(tasklet):
+ r = weakref.ref(tasklet)
+ info = _weak_tasklet_registered_to_info.get(r)
+ if info is None:
+ info = _weak_tasklet_registered_to_info[r] = _TaskletInfo(r, tasklet)
+
+ return info
+
+
+_application_set_schedule_callback = None
+
+#=======================================================================================================================
+# _schedule_callback
+#=======================================================================================================================
+def _schedule_callback(prev, next):
+ '''
+ Called when a context is stopped or a new context is made runnable.
+ '''
+ try:
+ if not prev and not next:
+ return
+
+ current_frame = sys._getframe()
+
+ if next:
+ register_tasklet_info(next)
+
+ # Ok, making next runnable: set the tracing facility in it.
+ debugger = GetGlobalDebugger()
+ if debugger is not None:
+ next.trace_function = debugger.trace_dispatch
+ frame = next.frame
+ if frame is current_frame:
+ frame = frame.f_back
+ if hasattr(frame, 'f_trace'): # Note: can be None (but hasattr should cover for that too).
+ frame.f_trace = debugger.trace_dispatch
+
+ debugger = None
+
+ if prev:
+ register_tasklet_info(prev)
+
+ try:
+ for tasklet_ref, tasklet_info in list(_weak_tasklet_registered_to_info.items()): # Make sure it's a copy!
+ tasklet = tasklet_ref()
+ if tasklet is None or not tasklet.alive:
+ # Garbage-collected already!
+ try:
+ del _weak_tasklet_registered_to_info[tasklet_ref]
+ except KeyError:
+ pass
+ if tasklet_info.frame_id is not None:
+ removeCustomFrame(tasklet_info.frame_id)
+ else:
+ is_running = stackless.get_thread_info(tasklet.thread_id)[1] is tasklet
+ if tasklet is prev or (tasklet is not next and not is_running):
+ # the tasklet won't run after this scheduler action:
+ # - the tasklet is the previous tasklet
+ # - it is not the next tasklet and it is not an already running tasklet
+ frame = tasklet.frame
+ if frame is current_frame:
+ frame = frame.f_back
+ if frame is not None:
+ _filename, base = GetFilenameAndBase(frame)
+ # print >>sys.stderr, "SchedCB: %r, %d, '%s', '%s'" % (tasklet, frame.f_lineno, _filename, base)
+ is_file_to_ignore = DictContains(DONT_TRACE, base)
+ if not is_file_to_ignore:
+ tasklet_info.update_name()
+ if tasklet_info.frame_id is None:
+ tasklet_info.frame_id = addCustomFrame(frame, tasklet_info.tasklet_name, tasklet.thread_id)
+ else:
+ updateCustomFrame(tasklet_info.frame_id, frame, tasklet.thread_id, name=tasklet_info.tasklet_name)
+
+ elif tasklet is next or is_running:
+ if tasklet_info.frame_id is not None:
+ # Remove info about stackless suspended when it starts to run.
+ removeCustomFrame(tasklet_info.frame_id)
+ tasklet_info.frame_id = None
+
+
+ finally:
+ tasklet = None
+ tasklet_info = None
+ frame = None
+
+ except:
+ import traceback;traceback.print_exc()
+
+ if _application_set_schedule_callback is not None:
+ return _application_set_schedule_callback(prev, next)
+
+if not hasattr(stackless.tasklet, "trace_function"):
+ # Older versions of Stackless, released before 2014
+ # This code does not work reliable! It is affected by several
+ # stackless bugs: Stackless issues #44, #42, #40
+ def _schedule_callback(prev, next):
+ '''
+ Called when a context is stopped or a new context is made runnable.
+ '''
+ try:
+ if not prev and not next:
+ return
+
+ if next:
+ register_tasklet_info(next)
+
+ # Ok, making next runnable: set the tracing facility in it.
+ debugger = GetGlobalDebugger()
+ if debugger is not None and next.frame:
+ if hasattr(next.frame, 'f_trace'):
+ next.frame.f_trace = debugger.trace_dispatch
+ debugger = None
+
+ if prev:
+ register_tasklet_info(prev)
+
+ try:
+ for tasklet_ref, tasklet_info in list(_weak_tasklet_registered_to_info.items()): # Make sure it's a copy!
+ tasklet = tasklet_ref()
+ if tasklet is None or not tasklet.alive:
+ # Garbage-collected already!
+ try:
+ del _weak_tasklet_registered_to_info[tasklet_ref]
+ except KeyError:
+ pass
+ if tasklet_info.frame_id is not None:
+ removeCustomFrame(tasklet_info.frame_id)
+ else:
+ if tasklet.paused or tasklet.blocked or tasklet.scheduled:
+ if tasklet.frame and tasklet.frame.f_back:
+ f_back = tasklet.frame.f_back
+ _filename, base = GetFilenameAndBase(f_back)
+ is_file_to_ignore = DictContains(DONT_TRACE, base)
+ if not is_file_to_ignore:
+ if tasklet_info.frame_id is None:
+ tasklet_info.frame_id = addCustomFrame(f_back, tasklet_info.tasklet_name, tasklet.thread_id)
+ else:
+ updateCustomFrame(tasklet_info.frame_id, f_back, tasklet.thread_id)
+
+ elif tasklet.is_current:
+ if tasklet_info.frame_id is not None:
+ # Remove info about stackless suspended when it starts to run.
+ removeCustomFrame(tasklet_info.frame_id)
+ tasklet_info.frame_id = None
+
+ finally:
+ tasklet = None
+ tasklet_info = None
+ f_back = None
+
+ except:
+ import traceback;traceback.print_exc()
+
+ if _application_set_schedule_callback is not None:
+ return _application_set_schedule_callback(prev, next)
+
+
+ _original_setup = stackless.tasklet.setup
+
+ #=======================================================================================================================
+ # setup
+ #=======================================================================================================================
+ def setup(self, *args, **kwargs):
+ '''
+ Called to run a new tasklet: rebind the creation so that we can trace it.
+ '''
+
+ f = self.tempval
+ def new_f(old_f, args, kwargs):
+
+ debugger = GetGlobalDebugger()
+ if debugger is not None:
+ SetTrace(debugger.trace_dispatch)
+
+ debugger = None
+
+ # Remove our own traces :)
+ self.tempval = old_f
+ register_tasklet_info(self)
+
+ # Hover old_f to see the stackless being created and *args and **kwargs to see its parameters.
+ return old_f(*args, **kwargs)
+
+ # This is the way to tell stackless that the function it should execute is our function, not the original one. Note:
+ # setting tempval is the same as calling bind(new_f), but it seems that there's no other way to get the currently
+ # bound function, so, keeping on using tempval instead of calling bind (which is actually the same thing in a better
+ # API).
+
+ self.tempval = new_f
+
+ return _original_setup(self, f, args, kwargs)
+
+ #=======================================================================================================================
+ # __call__
+ #=======================================================================================================================
+ def __call__(self, *args, **kwargs):
+ '''
+ Called to run a new tasklet: rebind the creation so that we can trace it.
+ '''
+
+ return setup(self, *args, **kwargs)
+
+
+ _original_run = stackless.run
+
+
+ #=======================================================================================================================
+ # run
+ #=======================================================================================================================
+ def run(*args, **kwargs):
+ debugger = GetGlobalDebugger()
+ if debugger is not None:
+ SetTrace(debugger.trace_dispatch)
+ debugger = None
+
+ return _original_run(*args, **kwargs)
+
+
+
+#=======================================================================================================================
+# patch_stackless
+#=======================================================================================================================
+def patch_stackless():
+ '''
+ This function should be called to patch the stackless module so that new tasklets are properly tracked in the
+ debugger.
+ '''
+ global _application_set_schedule_callback
+ _application_set_schedule_callback = stackless.set_schedule_callback(_schedule_callback)
+
+ def set_schedule_callback(callable):
+ global _application_set_schedule_callback
+ old = _application_set_schedule_callback
+ _application_set_schedule_callback = callable
+ return old
+
+ def get_schedule_callback(callable):
+ global _application_set_schedule_callback
+ return _application_set_schedule_callback
+
+ set_schedule_callback.__doc__ = stackless.set_schedule_callback.__doc__
+ if hasattr(stackless, "get_schedule_callback"):
+ get_schedule_callback.__doc__ = stackless.get_schedule_callback.__doc__
+ stackless.set_schedule_callback = set_schedule_callback
+ stackless.get_schedule_callback = get_schedule_callback
+
+ if not hasattr(stackless.tasklet, "trace_function"):
+ # Older versions of Stackless, released before 2014
+ __call__.__doc__ = stackless.tasklet.__call__.__doc__
+ stackless.tasklet.__call__ = __call__
+
+ setup.__doc__ = stackless.tasklet.setup.__doc__
+ stackless.tasklet.setup = setup
+
+ run.__doc__ = stackless.run.__doc__
+ stackless.run = run
+
+patch_stackless = call_only_once(patch_stackless)
diff --git a/python/helpers/pydev/pydevd_tracing.py b/python/helpers/pydev/pydevd_tracing.py
index 7c197efc2002..1a5a833f6bd0 100644
--- a/python/helpers/pydev/pydevd_tracing.py
+++ b/python/helpers/pydev/pydevd_tracing.py
@@ -68,6 +68,11 @@ def _InternalSetTrace(tracing_func):
TracingFunctionHolder._original_tracing(tracing_func)
def SetTrace(tracing_func):
+ if TracingFunctionHolder._original_tracing is None:
+ #This may happen before ReplaceSysSetTraceFunc is called.
+ sys.settrace(tracing_func)
+ return
+
TracingFunctionHolder._lock.acquire()
try:
TracingFunctionHolder._warn = False
@@ -75,8 +80,8 @@ def SetTrace(tracing_func):
TracingFunctionHolder._warn = True
finally:
TracingFunctionHolder._lock.release()
-
-
+
+
def ReplaceSysSetTraceFunc():
if TracingFunctionHolder._original_tracing is None:
TracingFunctionHolder._original_tracing = sys.settrace
diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py
index b8f95fc62a24..de8c2415fcae 100644
--- a/python/helpers/pydev/pydevd_vars.py
+++ b/python/helpers/pydev/pydevd_vars.py
@@ -6,6 +6,7 @@ from django_frame import DjangoTemplateFrame
from pydevd_constants import * #@UnusedWildImport
from types import * #@UnusedWildImport
+from pydevd_custom_frames import getCustomFrame
from pydevd_xml import *
try:
@@ -20,11 +21,15 @@ else:
import threading
import pydevd_resolver
import traceback
+import pydevd_save_locals
+from pydev_imports import Exec, quote, execfile
try:
- from pydevd_exec import Exec
+ import types
+ frame_type = types.FrameType
except:
- from pydevd_exec2 import Exec
+ frame_type = None
+
#-------------------------------------------------------------------------- defining true and false for earlier versions
@@ -53,7 +58,7 @@ if USE_PSYCO_OPTIMIZATION:
sys.exc_clear() #don't keep the traceback -- clients don't want to see it
def iterFrames(initialFrame):
- """NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)"""
+ '''NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)'''
#cannot use yield
frames = []
@@ -90,65 +95,77 @@ def removeAdditionalFrameById(thread_id):
+
def findFrame(thread_id, frame_id):
""" returns a frame on the thread that has a given frame_id """
- if thread_id != GetThreadId(threading.currentThread()):
- raise VariableError("findFrame: must execute on same thread")
+ try:
+ curr_thread_id = GetThreadId(threading.currentThread())
+ if thread_id != curr_thread_id :
+ try:
+ return getCustomFrame(thread_id, frame_id) #I.e.: thread_id could be a stackless frame id + thread_id.
+ except:
+ pass
- lookingFor = int(frame_id)
+ raise VariableError("findFrame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id))
- if AdditionalFramesContainer.additional_frames:
- if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
- frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
+ lookingFor = int(frame_id)
- if frame is not None:
- return frame
+ if AdditionalFramesContainer.additional_frames:
+ if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
+ frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
- curFrame = GetFrame()
- if frame_id == "*":
- return curFrame # any frame is specified with "*"
+ if frame is not None:
+ return frame
- frameFound = None
+ curFrame = GetFrame()
+ if frame_id == "*":
+ return curFrame # any frame is specified with "*"
+
+ frameFound = None
+
+ for frame in iterFrames(curFrame):
+ if lookingFor == id(frame):
+ frameFound = frame
+ del frame
+ break
- for frame in iterFrames(curFrame):
- if lookingFor == id(frame):
- frameFound = frame
del frame
- break
- del frame
+ #Important: python can hold a reference to the frame from the current context
+ #if an exception is raised, so, if we don't explicitly add those deletes
+ #we might have those variables living much more than we'd want to.
- #Important: python can hold a reference to the frame from the current context
- #if an exception is raised, so, if we don't explicitly add those deletes
- #we might have those variables living much more than we'd want to.
+ #I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
+ #need to call sys.exc_clear())
+ del curFrame
- #I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
- #need to call sys.exc_clear())
- del curFrame
+ if frameFound is None:
+ msgFrames = ''
+ i = 0
- if frameFound is None:
- msgFrames = ''
- i = 0
+ for frame in iterFrames(GetFrame()):
+ i += 1
+ msgFrames += str(id(frame))
+ if i % 5 == 0:
+ msgFrames += '\n'
+ else:
+ msgFrames += ' - '
- for frame in iterFrames(GetFrame()):
- i += 1
- msgFrames += str(id(frame))
- if i % 5 == 0:
- msgFrames += '\n'
- else:
- msgFrames += ' - '
+ errMsg = '''findFrame: frame not found.
+ Looking for thread_id:%s, frame_id:%s
+ Current thread_id:%s, available frames:
+ %s\n
+ ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
- errMsg = '''findFrame: frame not found.
-Looking for thread_id:%s, frame_id:%s
-Current thread_id:%s, available frames:
-%s
-''' % (thread_id, lookingFor, GetThreadId(threading.currentThread()), msgFrames)
+ sys.stderr.write(errMsg)
+ return None
- sys.stderr.write(errMsg)
+ return frameFound
+ except:
+ import traceback
+ traceback.print_exc()
return None
- return frameFound
-
def resolveCompoundVariable(thread_id, frame_id, scope, attrs):
""" returns the value of the compound variable as a dictionary"""
frame = findFrame(thread_id, frame_id)
@@ -195,9 +212,9 @@ def resolveVar(var, attrs):
def evaluateExpression(thread_id, frame_id, expression, doExec):
- """returns the result of the evaluated expression
+ '''returns the result of the evaluated expression
@param doExec: determines if we should do an exec or an eval
- """
+ '''
frame = findFrame(thread_id, frame_id)
if frame is None:
return
@@ -210,7 +227,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
#See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
updated_globals = {}
updated_globals.update(frame.f_globals)
- updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
+ updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
try:
if doExec:
@@ -220,6 +237,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
compiled = compile(expression, '<string>', 'eval')
except:
Exec(expression, updated_globals, frame.f_locals)
+ pydevd_save_locals.save_locals(frame)
else:
result = eval(compiled, updated_globals, frame.f_locals)
if result is not None: #Only print if it's not None (as python does)
@@ -254,11 +272,11 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
del frame
def changeAttrExpression(thread_id, frame_id, attr, expression):
- """Changes some attribute in a given frame.
+ '''Changes some attribute in a given frame.
@note: it will not (currently) work if we're not in the topmost frame (that's a python
deficiency -- and it appears that there is no way of making it currently work --
will probably need some change to the python internals)
- """
+ '''
frame = findFrame(thread_id, frame_id)
if frame is None:
return
@@ -269,16 +287,7 @@ def changeAttrExpression(thread_id, frame_id, attr, expression):
try:
expression = expression.replace('@LINE@', '\n')
- #tests (needs proposed patch in python accepted)
- # if hasattr(frame, 'savelocals'):
- # if attr in frame.f_locals:
- # frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
- # frame.savelocals()
- # return
- #
- # elif attr in frame.f_globals:
- # frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
- # return
+
if attr[:7] == "Globals":
@@ -287,6 +296,11 @@ def changeAttrExpression(thread_id, frame_id, attr, expression):
frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
return frame.f_globals[attr]
else:
+ if pydevd_save_locals.is_save_locals_available():
+ frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
+ pydevd_save_locals.save_locals(frame)
+ return
+
#default way (only works for changing it in the topmost frame)
result = eval(expression, frame.f_globals, frame.f_locals)
Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
diff --git a/python/helpers/pydev/pydevd_xml.py b/python/helpers/pydev/pydevd_xml.py
index 73258e6fcc65..ac3f71cd9566 100644
--- a/python/helpers/pydev/pydevd_xml.py
+++ b/python/helpers/pydev/pydevd_xml.py
@@ -2,12 +2,14 @@ import pydev_log
import traceback
import pydevd_resolver
from pydevd_constants import * #@UnusedWildImport
-from types import * #@UnusedWildImport
+
+from pydev_imports import quote
try:
- from urllib import quote
+ import types
+ frame_type = types.FrameType
except:
- from urllib.parse import quote #@UnresolvedImport
+ frame_type = None
try:
from xml.sax.saxutils import escape
@@ -60,9 +62,18 @@ if not sys.platform.startswith("java"):
except:
pass #not available on all python versions
+ try:
+ import numpy
+ typeMap.append((numpy.ndarray, pydevd_resolver.ndarrayResolver))
+ except:
+ pass #numpy may not be installed
+
+ if frame_type is not None:
+ typeMap.append((frame_type, pydevd_resolver.frameResolver))
+
+
else: #platform is java
from org.python import core #@UnresolvedImport
-
typeMap = [
(core.PyNone, None),
(core.PyInteger, None),
@@ -98,20 +109,21 @@ def getType(o):
return 'Unable to get Type', 'Unable to get Type', None
try:
+
if type_name == 'org.python.core.PyJavaInstance':
- return type_object, type_name, pydevd_resolver.instanceResolver
+ return (type_object, type_name, pydevd_resolver.instanceResolver)
if type_name == 'org.python.core.PyArray':
- return type_object, type_name, pydevd_resolver.jyArrayResolver
+ return (type_object, type_name, pydevd_resolver.jyArrayResolver)
for t in typeMap:
if isinstance(o, t[0]):
- return type_object, type_name, t[1]
+ return (type_object, type_name, t[1])
except:
traceback.print_exc()
#no match return default
- return type_object, type_name, pydevd_resolver.defaultResolver
+ return (type_object, type_name, pydevd_resolver.defaultResolver)
def frameVarsToXML(frame_f_locals):
""" dumps frame variables to XML