diff options
author | Tor Norbye <tnorbye@google.com> | 2014-05-28 17:06:51 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-05-28 17:06:55 -0700 |
commit | c667c1f74abd96a2098520effdd5afdff7f0d34b (patch) | |
tree | ab650b0e69fb57d40350579d8796da74d8ea49cb /python/helpers/pydev | |
parent | 0f831a730c50607e2ffd95020875af6185e17734 (diff) | |
download | idea-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')
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("&", "&") + + 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 |