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
diff --git a/python/build/python-community-build.iml b/python/build/python-community-build.iml
index 9dcf7ca..bda1778 100644
--- a/python/build/python-community-build.iml
+++ b/python/build/python-community-build.iml
@@ -3,7 +3,6 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
- <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
diff --git a/python/src/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java b/python/gen/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java
similarity index 93%
rename from python/src/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java
rename to python/gen/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java
index 48fce32..cd94d72 100644
--- a/python/src/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java
+++ b/python/gen/com/jetbrains/python/buildout/config/lexer/_BuildoutCfgFlexLexer.java
@@ -1,20 +1,4 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* The following code was generated by JFlex 1.4.3 on 8/26/10 7:31 PM */
+/* The following code was generated by JFlex 1.4.3 on 4/26/14 11:32 AM */
package com.jetbrains.python.buildout.config.lexer;
@@ -27,8 +11,8 @@
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
- * on 8/26/10 7:31 PM from the specification file
- * <tt>C:/Projects/IDEA/tools/lexer/../../python/src/com/jetbrains/python/buildout/config/lexer/buildout.cfg.flex</tt>
+ * on 4/26/14 11:32 AM from the specification file
+ * <tt>/Users/ignatov/src/ultimate/tools/lexer/../../community/python/src/com/jetbrains/python/buildout/config/lexer/buildout.cfg.flex</tt>
*/
public class _BuildoutCfgFlexLexer implements FlexLexer, BuildoutCfgTokenTypes {
/** initial size of the lookahead buffer */
@@ -448,7 +432,7 @@
while (true) {
if (zzCurrentPosL < zzEndReadL)
- zzInput = zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++]:zzBufferL.charAt(zzCurrentPosL++);
+ zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
else if (zzAtEOF) {
zzInput = YYEOF;
break zzForAction;
@@ -468,7 +452,7 @@
break zzForAction;
}
else {
- zzInput = zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++]:zzBufferL.charAt(zzCurrentPosL++);
+ zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
}
}
int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
@@ -505,22 +489,6 @@
{ yybegin(IN_VALUE); return KEY_VALUE_SEPARATOR;
}
case 15: break;
- case 6:
- { return SECTION_NAME;
- }
- case 16: break;
- case 5:
- { yybegin(YYINITIAL); return COMMENT;
- }
- case 17: break;
- case 2:
- { return WHITESPACE;
- }
- case 18: break;
- case 8:
- { yybegin(YYINITIAL); return RBRACKET;
- }
- case 19: break;
case 10:
{ CharSequence matched = yytext();
int ind = matched.toString().indexOf(" ;");
@@ -532,6 +500,22 @@
}
return VALUE_CHARACTERS;
}
+ case 16: break;
+ case 6:
+ { return SECTION_NAME;
+ }
+ case 17: break;
+ case 5:
+ { yybegin(YYINITIAL); return COMMENT;
+ }
+ case 18: break;
+ case 2:
+ { return WHITESPACE;
+ }
+ case 19: break;
+ case 8:
+ { yybegin(YYINITIAL); return RBRACKET;
+ }
case 20: break;
case 1:
{ yybegin(IN_KEY_VALUE_SEPARATOR); return KEY_CHARACTERS;
diff --git a/python/src/com/jetbrains/python/lexer/_PythonLexer.java b/python/gen/com/jetbrains/python/lexer/_PythonLexer.java
similarity index 98%
rename from python/src/com/jetbrains/python/lexer/_PythonLexer.java
rename to python/gen/com/jetbrains/python/lexer/_PythonLexer.java
index bbb3bfa..214557a 100644
--- a/python/src/com/jetbrains/python/lexer/_PythonLexer.java
+++ b/python/gen/com/jetbrains/python/lexer/_PythonLexer.java
@@ -1,20 +1,4 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* The following code was generated by JFlex 1.4.3 on 6/19/13 1:28 PM */
+/* The following code was generated by JFlex 1.4.3 on 4/26/14 11:33 AM */
/* It's an automatically generated code. Do not modify it. */
package com.jetbrains.python.lexer;
@@ -28,8 +12,8 @@
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
- * on 6/19/13 1:28 PM from the specification file
- * <tt>/home/ktisha/IDEA/tools/lexer/../../python/src/com/jetbrains/python/lexer/Python.flex</tt>
+ * on 4/26/14 11:33 AM from the specification file
+ * <tt>/Users/ignatov/src/ultimate/tools/lexer/../../community/python/src/com/jetbrains/python/lexer/Python.flex</tt>
*/
class _PythonLexer implements FlexLexer {
/** initial size of the lookahead buffer */
diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeLexer.java b/python/gen/com/jetbrains/python/psi/types/PyTypeLexer.java
similarity index 94%
rename from python/src/com/jetbrains/python/psi/types/PyTypeLexer.java
rename to python/gen/com/jetbrains/python/psi/types/PyTypeLexer.java
index 80d99fd8..c3596b1 100644
--- a/python/src/com/jetbrains/python/psi/types/PyTypeLexer.java
+++ b/python/gen/com/jetbrains/python/psi/types/PyTypeLexer.java
@@ -1,20 +1,4 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* The following code was generated by JFlex 1.4.3 on 7/23/13 5:34 PM */
+/* The following code was generated by JFlex 1.4.3 on 4/26/14 11:34 AM */
package com.jetbrains.python.psi.types;
@@ -27,8 +11,8 @@
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
- * on 7/23/13 5:34 PM from the specification file
- * <tt>/home/user/src/idea/tools/lexer/../../python/src/com/jetbrains/python/psi/types/PyType.flex</tt>
+ * on 4/26/14 11:34 AM from the specification file
+ * <tt>/Users/ignatov/src/ultimate/tools/lexer/../../community/python/src/com/jetbrains/python/psi/types/PyType.flex</tt>
*/
public class PyTypeLexer implements FlexLexer {
/** initial size of the lookahead buffer */
diff --git a/python/src/icons/PythonIcons.java b/python/gen/icons/PythonIcons.java
similarity index 100%
rename from python/src/icons/PythonIcons.java
rename to python/gen/icons/PythonIcons.java
diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py
index 5be1df8..50e9119 100644
--- a/python/helpers/generator3.py
+++ b/python/helpers/generator3.py
@@ -388,7 +388,7 @@
if "-z" in opts:
if len(args) != 1:
- report("Expected 1 arg with -S, got %d args", len(args))
+ report("Expected 1 arg with -z, got %d args", len(args))
sys.exit(1)
zip_sources(args[0])
sys.exit(0)
diff --git a/python/helpers/pycharm/django_test_manage.py b/python/helpers/pycharm/django_test_manage.py
index 44b7c7c..afdf791 100644
--- a/python/helpers/pycharm/django_test_manage.py
+++ b/python/helpers/pycharm/django_test_manage.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
-import os, sys
+import os
+import sys
from django.core.management import ManagementUtility
@@ -15,7 +16,6 @@
except:
pass
-import django_test_runner
project_directory = sys.argv.pop()
from django.core import management
@@ -46,6 +46,9 @@
if not settings_file:
settings_file = 'settings'
+import django
+if django.VERSION[0:2] >= (1, 7):
+ django.setup()
class PycharmTestCommand(Command):
def get_runner(self):
diff --git a/python/helpers/pycharm/django_test_runner.py b/python/helpers/pycharm/django_test_runner.py
index 52fd470..e72affd 100644
--- a/python/helpers/pycharm/django_test_runner.py
+++ b/python/helpers/pycharm/django_test_runner.py
@@ -8,14 +8,14 @@
from django.conf import settings
if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER:
- from nose_utils import TeamcityNoseRunner
+ from nose_utils import TeamcityNoseRunner
from django.test.testcases import TestCase
from django import VERSION
try:
- from django.utils import unittest
+ from django.utils import unittest
except ImportError:
- import unittest
+ import unittest
def get_test_suite_runner():
if hasattr(settings, "TEST_RUNNER"):
@@ -43,7 +43,7 @@
class BaseRunner(TeamcityTestRunner, BaseSuiteRunner):
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self, stream)
- BaseSuiteRunner.__init__(self)
+ BaseSuiteRunner.__init__(self, **options)
except ImportError:
# for Django <= 1.1 compatibility
@@ -59,7 +59,7 @@
class DjangoTeamcityTestResult(TeamcityTestResult):
def __init__(self, *args, **kwargs):
- super(DjangoTeamcityTestResult, self).__init__()
+ super(DjangoTeamcityTestResult, self).__init__(**kwargs)
def _getSuite(self, test):
if hasattr(test, "suite"):
@@ -81,7 +81,8 @@
class DjangoTeamcityTestRunner(BaseRunner):
def __init__(self, stream=sys.stdout, **options):
- super(DjangoTeamcityTestRunner, self).__init__(stream)
+ super(DjangoTeamcityTestRunner, self).__init__(stream, **options)
+ self.options = options
def _makeResult(self, **kwargs):
return DjangoTeamcityTestResult(self.stream, **kwargs)
@@ -112,21 +113,19 @@
config.plugins.addPlugins(extraplugins=plugins_to_add)
for plugin in _get_plugins_from_settings():
- plugins_to_add.append(plugin)
+ plugins_to_add.append(plugin)
nose.core.TestProgram(argv=suite, exit=False, addplugins=plugins_to_add,
- testRunner=TeamcityNoseRunner(config=config)
- )
+ testRunner=TeamcityNoseRunner(config=config))
return result_plugin.result
else:
- return TeamcityTestRunner.run(self, suite, **kwargs)
+ self.options.update(kwargs)
+ return TeamcityTestRunner.run(self, suite, **self.options)
def run_tests(self, test_labels, extra_tests=None, **kwargs):
if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER:
- return super(DjangoTeamcityTestRunner, self).run_tests(test_labels,
- extra_tests)
- return super(DjangoTeamcityTestRunner, self).run_tests(test_labels,
- extra_tests, **kwargs)
+ return super(DjangoTeamcityTestRunner, self).run_tests(test_labels, extra_tests)
+ return super(DjangoTeamcityTestRunner, self).run_tests(test_labels, extra_tests, **kwargs)
def partition_suite(suite, classes, bins):
@@ -169,33 +168,33 @@
def run_the_old_way(extra_tests, kwargs, test_labels, verbosity):
- from django.test.simple import build_suite, build_test, get_app, get_apps, \
- setup_test_environment, teardown_test_environment
+ from django.test.simple import build_suite, build_test, get_app, get_apps, \
+ setup_test_environment, teardown_test_environment
- setup_test_environment()
- settings.DEBUG = False
- suite = unittest.TestSuite()
- if test_labels:
- for label in test_labels:
- if '.' in label:
- suite.addTest(build_test(label))
- else:
- app = get_app(label)
- suite.addTest(build_suite(app))
- else:
- for app in get_apps():
- suite.addTest(build_suite(app))
- for test in extra_tests:
- suite.addTest(test)
- suite = reorder_suite(suite, (TestCase,))
- old_name = settings.DATABASE_NAME
- from django.db import connection
+ setup_test_environment()
+ settings.DEBUG = False
+ suite = unittest.TestSuite()
+ if test_labels:
+ for label in test_labels:
+ if '.' in label:
+ suite.addTest(build_test(label))
+ else:
+ app = get_app(label)
+ suite.addTest(build_suite(app))
+ else:
+ for app in get_apps():
+ suite.addTest(build_suite(app))
+ for test in extra_tests:
+ suite.addTest(test)
+ suite = reorder_suite(suite, (TestCase,))
+ old_name = settings.DATABASE_NAME
+ from django.db import connection
- connection.creation.create_test_db(verbosity, autoclobber=False)
- result = DjangoTeamcityTestRunner().run(suite, **kwargs)
- connection.creation.destroy_test_db(old_name, verbosity)
- teardown_test_environment()
- return len(result.failures) + len(result.errors)
+ connection.creation.create_test_db(verbosity, autoclobber=False)
+ result = DjangoTeamcityTestRunner().run(suite, **kwargs)
+ connection.creation.destroy_test_db(old_name, verbosity)
+ teardown_test_environment()
+ return len(result.failures) + len(result.errors)
def run_tests(test_labels, verbosity=1, interactive=False, extra_tests=[],
@@ -218,9 +217,14 @@
Returns the number of tests that failed.
"""
+ options = {
+ 'verbosity': verbosity,
+ 'interactive': interactive
+ }
+ options.update(kwargs)
TeamcityServiceMessages(sys.stdout).testMatrixEntered()
if VERSION[1] > 1:
- return DjangoTeamcityTestRunner().run_tests(test_labels,
- extra_tests=extra_tests, **kwargs)
+ return DjangoTeamcityTestRunner(**options).run_tests(test_labels,
+ extra_tests=extra_tests, **options)
- return run_the_old_way(extra_tests, kwargs, test_labels, verbosity)
+ return run_the_old_way(extra_tests, options, test_labels, verbosity)
\ No newline at end of file
diff --git a/python/helpers/pycharm/pycharm_load_entry_point.py b/python/helpers/pycharm/pycharm_load_entry_point.py
new file mode 100644
index 0000000..f03286c
--- /dev/null
+++ b/python/helpers/pycharm/pycharm_load_entry_point.py
@@ -0,0 +1,9 @@
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+ name = sys.argv.pop()
+ dist = sys.argv.pop()
+ sys.exit(
+ load_entry_point(dist, "console_scripts", name)()
+ )
diff --git a/python/helpers/pycharm/utrunner.py b/python/helpers/pycharm/utrunner.py
index 1f11206..3ae5cd2 100644
--- a/python/helpers/pycharm/utrunner.py
+++ b/python/helpers/pycharm/utrunner.py
@@ -108,7 +108,7 @@
debug("/ from folder " + a_splitted[0] + ". Use pattern: " + a_splitted[1])
modules = loadModulesFromFolderRec(a_splitted[0], a_splitted[1])
else:
- if a[0].endswith("/"):
+ if a[0].endswith(os.path.sep):
debug("/ from folder " + a[0])
modules = loadModulesFromFolderRec(a[0])
else:
diff --git a/python/helpers/pydev/_completer.py b/python/helpers/pydev/_pydev_completer.py
similarity index 71%
rename from python/helpers/pydev/_completer.py
rename to python/helpers/pydev/_pydev_completer.py
index 4d34fec..93e0bfa 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 @@
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 @@
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 1d8e141..d60d7ed 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 0000000..670625f
--- /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
similarity index 98%
rename from python/helpers/pydev/importsTipper.py
rename to python/helpers/pydev/_pydev_imports_tipper.py
index 97fc76a..e4b3b86 100644
--- a/python/helpers/pydev/importsTipper.py
+++ b/python/helpers/pydev/_pydev_imports_tipper.py
@@ -2,7 +2,7 @@
import inspect
import sys
-from _tipper_common import DoFind
+from _pydev_tipper_common import DoFind
#completion types.
@@ -151,7 +151,9 @@
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
similarity index 99%
rename from python/helpers/pydev/jyimportsTipper.py
rename to python/helpers/pydev/_pydev_jy_imports_tipper.py
index cd8da26..43e4d0b 100644
--- a/python/helpers/pydev/jyimportsTipper.py
+++ b/python/helpers/pydev/_pydev_jy_imports_tipper.py
@@ -4,7 +4,7 @@
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
similarity index 100%
rename from python/helpers/pydev/_tipper_common.py
rename to 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 0000000..22d445a
--- /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 272888e..762df2d1 100644
--- a/python/helpers/pydev/django_frame.py
+++ b/python/helpers/pydev/django_frame.py
@@ -30,7 +30,7 @@
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 @@
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 f6056d0..103253e 100644
--- a/python/helpers/pydev/interpreterInfo.py
+++ b/python/helpers/pydev/interpreterInfo.py
@@ -6,138 +6,247 @@
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:
- #Just check if False and True are defined (depends on version, not whether it's jython/python)
+ 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)
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():
'''
- return os.path.normpath(path)
+ Note: there's a copy of this method in _pydev_filesystem_encoding.py
+ '''
+ 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 93dd2e8..e706d54 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 @@
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 fc4332f..2fdd539 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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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
-
- elif data.startswith(MSG_SEARCH):
- data = data.replace(MSG_SEARCH, '')
+ self.send(MSG_OK)
+
+ elif data.startswith(MSG_JEDI):
+ data = data[len(MSG_JEDI):]
data = unquote_plus(data)
- (f, line, col), foundAs = importsTipper.Search(data)
- returnMsg = self.getCompletionsMessage(f, [(line, col, foundAs)])
-
+ 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[len(MSG_SEARCH):]
+ data = unquote_plus(data)
+ (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 @@
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 0000000..464f0dd
--- /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 54a8585..571ae87 100644
--- a/python/helpers/pydev/pydev_console_utils.py
+++ b/python/helpers/pydev/pydev_console_utils.py
@@ -215,7 +215,16 @@
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 @@
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 @@
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 9dce8c4..0685875 100644
--- a/python/helpers/pydev/pydev_imports.py
+++ b/python/helpers/pydev/pydev_imports.py
@@ -33,4 +33,61 @@
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 0000000..185d417
--- /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 0000000..e69de29
--- /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 0000000..c016b25
--- /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 0000000..f0683ba
--- /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 0000000..8c021d3
--- /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 0000000..f2ca39f
--- /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 0000000..0cbb87f
--- /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 0000000..f4f32a3
--- /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 0000000..e245cc0
--- /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 0000000..6640884
--- /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 0000000..71c2fbc
--- /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 0000000..b1c9865
--- /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 0000000..f480a08
--- /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 0000000..1de0047
--- /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 6a8e056..859157e 100644
--- a/python/helpers/pydev/pydev_ipython_console.py
+++ b/python/helpers/pydev/pydev_ipython_console.py
@@ -82,7 +82,7 @@
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 15c5b85..198d40f 100644
--- a/python/helpers/pydev/pydev_ipython_console_011.py
+++ b/python/helpers/pydev/pydev_ipython_console_011.py
@@ -84,13 +84,15 @@
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 @@
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 0000000..70bf765
--- /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 e8b8d29..7edf089 100644
--- a/python/helpers/pydev/pydevconsole.py
+++ b/python/helpers/pydev/pydevconsole.py
@@ -23,10 +23,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
sys.stderr.write(interpreter.get_greeting_msg())
+ sys.stderr.flush()
+ interpreter.server = server
server.serve_forever()
return server
@@ -312,6 +319,8 @@
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 5cd96b1..4a509d0 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 @@
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 @@
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 @@
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 @@
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 @@
pydev_start_new_thread = PydevStartNewThread()
+
#=======================================================================================================================
# PyDB
#=======================================================================================================================
@@ -272,11 +295,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
+ 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():
- self.SetTraceForFrameAndParents(frame)
- del frame
+ 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 @@
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 @@
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 @@
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()
+ thread_id = '*' # Any thread
- else:
- sys.stderr.write('pydev debugger: Reloading: '+module_name+'\n')
- sys.stderr.flush()
- xreload(sys.modules[module_name])
+ # 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
- 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 @@
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 @@
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])
+ # 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)
+ self.prepareToRun()
- pydevd_tracing.SetTrace(self.trace_dispatch)
- try:
- #not available in jython!
- threading.settrace(self.trace_dispatch) # for all future threads
- except:
- pass
+ while not self.readyToRun:
+ time.sleep(0.1) # busy wait until we receive run command
- try:
- thread.start_new_thread = pydev_start_new_thread
- thread.start_new = pydev_start_new_thread
- except:
- pass
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 d2d3fff..1b0fc2c 100644
--- a/python/helpers/pydev/pydevd_additional_thread_info.py
+++ b/python/helpers/pydev/pydevd_additional_thread_info.py
@@ -118,7 +118,7 @@
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 @@
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 b750536..9d4f2e7 100644
--- a/python/helpers/pydev/pydevd_comm.py
+++ b/python/helpers/pydev/pydevd_comm.py
@@ -89,22 +89,21 @@
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 @@
VERSION_STRING = "@@BUILD_NUMBER@@"
+from _pydev_filesystem_encoding import getfilesystemencoding
+file_system_encoding = getfilesystemencoding()
#--------------------------------------------------------------------------------------------------- UTILITIES
@@ -290,7 +291,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
# 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 5e78e15..71fe4ae 100644
--- a/python/helpers/pydev/pydevd_constants.py
+++ b/python/helpers/pydev/pydevd_constants.py
@@ -59,7 +59,7 @@
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 @@
# 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 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 @@
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 @@
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 0000000..e259356
--- /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 6cffeaf..9a342ee 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 9b234b7..ee4f37a 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 a91f160..05faaeb 100644
--- a/python/helpers/pydev/pydevd_frame.py
+++ b/python/helpers/pydev/pydevd_frame.py
@@ -210,6 +210,7 @@
return self.trace_dispatch
except:
+ traceback.print_exc()
raise
#step handling. We stop when we hit the right frame
@@ -339,45 +340,46 @@
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)
+ 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 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.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.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)
+ 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 c84b0ce..3c3bec8 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 ca8c493..a83adc8 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 @@
pass
def isatty(self):
- return False #not really a file
+ return False
def flush(self):
for r in self._redirectTo:
@@ -33,17 +37,22 @@
'''
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 @@
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 03ca2fd..1533c89 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):
+
+
+ A class or module may include a method called '__xreload_after_reload_update__' which is called
+ after the reload finishes.
+
+
+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).
+
+
+Current limitations
+======================
+
+
+- Attributes/constants are added, but not changed (so singletons and the application state is not
+ broken -- use provided hooks to workaround it).
+
+- Code using metaclasses may not always work.
+
+- Functions and methods using decorators (other than classmethod and staticmethod) are not 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.
+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.
-Some of the many limitations include:
-
-- Global mutable objects other than classes are simply replaced, not patched
-
-- Code using metaclasses is not handled correctly
-
-- Code creating global singletons is not handled correctly
-
-- Functions and methods using decorators (other than classmethod and
- staticmethod) is not handled correctly
-
-- Renamings are not handled correctly
-
-- Dependent modules are not reloaded
-
-- 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
-
-- Frozen modules and modules loaded from zip files aren't handled
- correctly
-
-- 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.
+ Returns a boolean indicating whether a change was done.
"""
- # 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
+ r = Reload(mod)
+ r.apply()
+ found_change = r.found_change
+ r = None
+ pydevd_dont_trace.clear_trace_filter_cache()
+ return found_change
-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.
- """
- 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
+# 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)
-# All of the following functions have the same signature as _update()
+#=======================================================================================================================
+# 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 _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 _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)
-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
+ 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_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(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()
-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
+ # All of the following functions have the same signature as _update()
-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
+ 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 114b849..614549f 100644
--- a/python/helpers/pydev/pydevd_resolver.py
+++ b/python/helpers/pydev/pydevd_resolver.py
@@ -3,6 +3,7 @@
except:
import io as StringIO
import traceback
+from os.path import basename
try:
__setFalse = False
@@ -357,9 +358,100 @@
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 0000000..2808081
--- /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 0000000..bd3b306
--- /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 7c197ef..1a5a833 100644
--- a/python/helpers/pydev/pydevd_tracing.py
+++ b/python/helpers/pydev/pydevd_tracing.py
@@ -68,6 +68,11 @@
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 @@
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 b8f95fc..de8c241 100644
--- a/python/helpers/pydev/pydevd_vars.py
+++ b/python/helpers/pydev/pydevd_vars.py
@@ -6,6 +6,7 @@
from pydevd_constants import * #@UnusedWildImport
from types import * #@UnusedWildImport
+from pydevd_custom_frames import getCustomFrame
from pydevd_xml import *
try:
@@ -20,11 +21,15 @@
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 @@
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 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 "*"
- for frame in iterFrames(curFrame):
- if lookingFor == id(frame):
- frameFound = frame
+ frameFound = None
+
+ for frame in iterFrames(curFrame):
+ if lookingFor == id(frame):
+ frameFound = frame
+ del frame
+ break
+
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 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 @@
#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 @@
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 @@
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 @@
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 @@
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 73258e6..ac3f71c 100644
--- a/python/helpers/pydev/pydevd_xml.py
+++ b/python/helpers/pydev/pydevd_xml.py
@@ -2,12 +2,14 @@
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 @@
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 @@
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
diff --git a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
index ed2163a..2d89427 100644
--- a/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
+++ b/python/ide/src/com/jetbrains/python/PythonSdkChooserCombo.java
@@ -15,10 +15,13 @@
*/
package com.jetbrains.python;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.CollectionComboBoxModel;
@@ -27,6 +30,7 @@
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.sdk.PyDetectedSdk;
+import com.jetbrains.python.sdk.PySdkService;
import com.jetbrains.python.sdk.PythonSdkDetailsStep;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.Nullable;
@@ -41,6 +45,7 @@
*/
public class PythonSdkChooserCombo extends ComboboxWithBrowseButton {
private final List<ActionListener> myChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList();
+ private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.PythonSdkChooserCombo");
@SuppressWarnings("unchecked")
public PythonSdkChooserCombo(final Project project, List<Sdk> sdks, final Condition<Sdk> acceptableSdkCondition) {
@@ -78,13 +83,26 @@
final PyConfigurableInterpreterList interpreterList = PyConfigurableInterpreterList.getInstance(project);
final Sdk[] sdks = interpreterList.getModel().getSdks();
PythonSdkDetailsStep.show(project, sdks, null, this, getButton().getLocationOnScreen(), new NullableConsumer<Sdk>() {
- @Override
- public void consume(@Nullable Sdk sdk) {
- //noinspection unchecked
- getComboBox().setModel(new CollectionComboBoxModel(interpreterList.getAllPythonSdks(), sdk));
+ @Override
+ public void consume(@Nullable Sdk sdk) {
+ if (sdk == null) return;
+ final PySdkService sdkService = PySdkService.getInstance();
+ sdkService.restoreSdk(sdk);
+
+ final ProjectSdksModel projectSdksModel = interpreterList.getModel();
+ if (projectSdksModel.findSdk(sdk) == null) {
+ projectSdksModel.addSdk(sdk);
+ try {
+ projectSdksModel.apply();
+ }
+ catch (ConfigurationException e) {
+ LOG.error("Error adding new python interpreter " + e.getMessage());
+ }
}
+ //noinspection unchecked
+ getComboBox().setModel(new CollectionComboBoxModel(interpreterList.getAllPythonSdks(), sdk));
}
- );
+ }, true);
}
private void notifyChanged(ActionEvent e) {
diff --git a/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java
index 199e9ed..8ece6bc 100644
--- a/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java
+++ b/python/ide/src/com/jetbrains/python/buildout/BuildoutConfigurable.java
@@ -87,7 +87,7 @@
@Nls
@Override
public String getDisplayName() {
- return "Buildout Support";
+ return "Buildout";
}
@Override
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonPathDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonPathDialog.java
new file mode 100644
index 0000000..c4c5765
--- /dev/null
+++ b/python/ide/src/com/jetbrains/python/configuration/PythonPathDialog.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.configuration;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.SideBorder;
+import com.jetbrains.python.ui.IdeaDialog;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class PythonPathDialog extends IdeaDialog {
+ private PythonPathEditor myEditor;
+
+ public PythonPathDialog(@NotNull final Project project, @NotNull final PythonPathEditor editor) {
+ super(project);
+ myEditor = editor;
+ init();
+ setTitle("Interpreter Paths");
+ }
+
+ @Override
+ protected JComponent createCenterPanel() {
+ JComponent mainPanel = myEditor.createComponent();
+ mainPanel.setPreferredSize(new Dimension(600, 400));
+ mainPanel.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL));
+
+ return mainPanel;
+ }
+
+}
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
index be4273d..6ff0a2e 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java
@@ -33,7 +33,6 @@
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
-import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
@@ -444,19 +443,6 @@
@Override
public void actionPerformed(AnActionEvent e) {
- DialogBuilder dialog = new DialogBuilder(myProject);
-
- final PythonPathEditor editor =
- new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
- @Override
- protected void onReloadButtonClicked() {
- reloadSdk();
- }
- };
- final JComponent component = editor.createComponent();
- component.setPreferredSize(new Dimension(600, 400));
- component.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL));
- dialog.setCenterPanel(component);
Sdk sdk = getSelectedSdk();
if (sdk instanceof PyDetectedSdk) {
final String sdkName = sdk.getName();
@@ -468,10 +454,25 @@
});
sdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null, null);
}
- editor.reload(sdk != null ? sdk.getSdkModificator(): null);
+ final PythonPathEditor pathEditor =
+ new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
+ @Override
+ protected void onReloadButtonClicked() {
+ reloadSdk();
+ }
+ };
+ final SdkModificator sdkModificator = myModificators.get(sdk);
- dialog.setTitle("Interpreter Paths");
+ PythonPathDialog dialog = new PythonPathDialog(myProject, pathEditor);
+ pathEditor.reset(sdk != null ? sdkModificator : null);
dialog.show();
+
+ if (dialog.isOK()) {
+ if (pathEditor.isModified()) {
+ pathEditor.apply(sdkModificator);
+ myModifiedModificators.add(sdkModificator);
+ }
+ }
updateOkButton();
}
}
diff --git a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java
index dd5671b..a58fdd6 100644
--- a/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java
+++ b/python/ide/src/com/jetbrains/python/newProject/PythonNewDirectoryProjectAction.java
@@ -86,7 +86,7 @@
for (Sdk sdk : sdks) {
final SdkAdditionalData additionalData = sdk.getSdkAdditionalData();
if (additionalData instanceof PythonSdkAdditionalData) {
- ((PythonSdkAdditionalData) additionalData).reassociateWithCreatedProject(newProject);
+ ((PythonSdkAdditionalData)additionalData).reassociateWithCreatedProject(newProject);
}
}
}
diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyExternalProcessException.java b/python/openapi/src/com/jetbrains/python/packaging/PyExternalProcessException.java
index 07745d8..40d1f31 100644
--- a/python/openapi/src/com/jetbrains/python/packaging/PyExternalProcessException.java
+++ b/python/openapi/src/com/jetbrains/python/packaging/PyExternalProcessException.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.packaging;
+import com.intellij.execution.ExecutionException;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
@@ -25,7 +26,7 @@
/**
* @author vlan
*/
-public class PyExternalProcessException extends Exception {
+public class PyExternalProcessException extends ExecutionException {
private static final Pattern WITH_CR_DELIMITER_PATTERN = Pattern.compile("(?<=\r|\n|\r\n)");
private final int myRetcode;
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java b/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java
index 12e4e47..509f835 100644
--- a/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java
@@ -45,7 +45,7 @@
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
- ShowSettingsUtil.getInstance().showSettingsDialog(project, "Template Languages");
+ ShowSettingsUtil.getInstance().showSettingsDialog(project, "Project Structure");
}
}, ModalityState.NON_MODAL);
}
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
index 4b1b8b4..eff10e1 100644
--- a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplatesService.java
@@ -20,6 +20,7 @@
import com.intellij.openapi.module.ModuleServiceManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -53,6 +54,7 @@
public abstract void setTemplateLanguage(String templateLanguage);
+ @NotNull
public abstract List<VirtualFile> getTemplateFolders();
public abstract void setTemplateFolders(VirtualFile... roots);
diff --git a/python/pluginResources/META-INF/plugin.xml b/python/pluginResources/META-INF/plugin.xml
index ebd6839..6ec30aa 100644
--- a/python/pluginResources/META-INF/plugin.xml
+++ b/python/pluginResources/META-INF/plugin.xml
@@ -4,7 +4,7 @@
<id>PythonCore</id>
<name>Python Community Edition</name>
- <idea-version since-build="135.406" until-build="136.*"/>
+ <idea-version since-build="135.406" until-build="138.*"/>
<description>Smart editing for Python scripts</description>
<version>3.4.Beta.135.@@BUILD_NUMBER@@</version>
<depends>com.intellij.modules.java</depends>
diff --git a/python/pluginSrc/com/jetbrains/python/module/PythonModuleBuilder.java b/python/pluginSrc/com/jetbrains/python/module/PythonModuleBuilder.java
index c86f89d..a14edc5 100644
--- a/python/pluginSrc/com/jetbrains/python/module/PythonModuleBuilder.java
+++ b/python/pluginSrc/com/jetbrains/python/module/PythonModuleBuilder.java
@@ -16,10 +16,14 @@
package com.jetbrains.python.module;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
+import com.intellij.ide.util.projectWizard.SdkSettingsStep;
+import com.intellij.ide.util.projectWizard.SettingsStep;
import com.intellij.ide.util.projectWizard.SourcePathsBuilder;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
+import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -47,8 +51,17 @@
}
@Override
- public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext,
- @NotNull ModulesProvider modulesProvider) {
- return getModuleType().createWizardSteps(wizardContext, this, modulesProvider);
+ public ModuleWizardStep modifyProjectTypeStep(@NotNull SettingsStep settingsStep) {
+ return new SdkSettingsStep(settingsStep, this, new Condition<SdkTypeId>() {
+ @Override
+ public boolean value(SdkTypeId id) {
+ return PythonSdkType.getInstance() == id;
+ }
+ }) {
+ @Override
+ protected void OnSdkSelected(Sdk sdk) {
+ setSdk(sdk);
+ }
+ };
}
}
diff --git a/python/pluginSrc/com/jetbrains/python/module/PythonModuleType.java b/python/pluginSrc/com/jetbrains/python/module/PythonModuleType.java
index 22de180..a8ff4ad 100644
--- a/python/pluginSrc/com/jetbrains/python/module/PythonModuleType.java
+++ b/python/pluginSrc/com/jetbrains/python/module/PythonModuleType.java
@@ -15,50 +15,13 @@
*/
package com.jetbrains.python.module;
-import com.intellij.facet.impl.DefaultFacetsProvider;
-import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
-import com.intellij.ide.util.frameworkSupport.FrameworkSupportUtil;
-import com.intellij.ide.util.newProjectWizard.SupportForFrameworksStep;
-import com.intellij.ide.util.projectWizard.ModuleWizardStep;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory;
import com.jetbrains.python.PythonModuleTypeBase;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* @author yole
*/
public class PythonModuleType extends PythonModuleTypeBase<PythonModuleBuilderBase> {
- @NotNull
- @Override
- public ModuleWizardStep[] createWizardSteps(@NotNull final WizardContext wizardContext,
- @NotNull final PythonModuleBuilderBase moduleBuilder,
- @NotNull final ModulesProvider modulesProvider) {
- ArrayList<ModuleWizardStep> steps = new ArrayList<ModuleWizardStep>();
- final Project project = getProject(wizardContext);
- steps.add(new PythonSdkSelectStep(moduleBuilder, "reference.project.structure.sdk.python", project));
- if (!wizardContext.isNewWizard()) {
- final List<FrameworkSupportInModuleProvider> providers = FrameworkSupportUtil.getProviders(getInstance(), DefaultFacetsProvider.INSTANCE);
- if (!providers.isEmpty()) {
- steps.add(new SupportForFrameworksStep(wizardContext, moduleBuilder, LibrariesContainerFactory.createContainer(project)));
- }
- }
- return steps.toArray(new ModuleWizardStep[steps.size()]);
- }
-
- private static Project getProject(final WizardContext context) {
- Project project = context.getProject();
- if (project == null) {
- project = ProjectManager.getInstance().getDefaultProject();
- }
- return project;
- }
@NotNull
public PythonModuleBuilder createModuleBuilder() {
diff --git a/python/pluginSrc/com/jetbrains/python/module/PythonSdkChooserPanel.java b/python/pluginSrc/com/jetbrains/python/module/PythonSdkChooserPanel.java
deleted file mode 100644
index 757ba05..0000000
--- a/python/pluginSrc/com/jetbrains/python/module/PythonSdkChooserPanel.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.module;
-
-import com.intellij.ide.util.projectWizard.JdkChooserPanel;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SdkType;
-import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.ui.MultiLineLabelUI;
-import com.intellij.util.ui.UIUtil;
-import com.jetbrains.python.sdk.PythonSdkType;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-/**
- * @author oleg, Roman.Chernyatchik
- */
-public class PythonSdkChooserPanel extends JComponent {
- private final JdkChooserPanel myJdkChooser;
-
- /**
- * PythonSdkChooserPanel - the panel to choose Python SDK
- *
- * @param project Current project
- */
- public PythonSdkChooserPanel(@NotNull final Project project) {
- myJdkChooser = new JdkChooserPanel(project);
-
- setLayout(new GridBagLayout());
- setBorder(BorderFactory.createEtchedBorder());
-
- final JLabel label = new JLabel("Specify the Python interpreter");
- label.setUI(new MultiLineLabelUI());
- add(label, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
- GridBagConstraints.HORIZONTAL, new Insets(8, 10, 8, 10), 0, 0));
-
- final JLabel jdkLabel = new JLabel("Python Interpreter:");
- jdkLabel.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD));
- add(jdkLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
- GridBagConstraints.NONE, new Insets(8, 10, 0, 10), 0, 0));
-
- add(myJdkChooser, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST,
- GridBagConstraints.BOTH, new Insets(2, 10, 10, 5), 0, 0));
- JButton configureButton = new JButton("Configure...");
- add(configureButton, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 1.0, GridBagConstraints.NORTHWEST,
- GridBagConstraints.NONE, new Insets(2, 0, 10, 5), 0, 0));
-
-
- configureButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- myJdkChooser.editJdkTable();
- }
- });
-
- myJdkChooser.setAllowedJdkTypes(new SdkType[]{PythonSdkType.getInstance()});
-
- final Sdk selectedJdk = project == null ? null : ProjectRootManager.getInstance(project).getProjectSdk();
- myJdkChooser.updateList(selectedJdk, null, null);
- }
-
- @Nullable
- public Sdk getChosenJdk() {
- return myJdkChooser.getChosenJdk();
- }
-
- public JComponent getPreferredFocusedComponent() {
- return myJdkChooser;
- }
-
- public void selectSdk(@Nullable final Sdk sdk) {
- myJdkChooser.selectJdk(sdk);
- }
-}
diff --git a/python/pluginSrc/com/jetbrains/python/module/PythonSdkSelectStep.java b/python/pluginSrc/com/jetbrains/python/module/PythonSdkSelectStep.java
deleted file mode 100644
index 92fa82c..0000000
--- a/python/pluginSrc/com/jetbrains/python/module/PythonSdkSelectStep.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.module;
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * @author oleg
- */
-public class PythonSdkSelectStep extends ModuleWizardStep {
- protected final PythonSdkChooserPanel myPanel;
- protected final PythonModuleBuilderBase mySettingsHolder;
-
- private final String myHelp;
-
- public PythonSdkSelectStep(@NotNull final PythonModuleBuilderBase settingsHolder,
- @Nullable final String helpId,
- @Nullable final Project project) {
- super();
- mySettingsHolder = settingsHolder;
- myPanel = new PythonSdkChooserPanel(project);
- myHelp = helpId;
- }
-
- public String getHelpId() {
- return myHelp;
- }
-
- public JComponent getPreferredFocusedComponent() {
- return myPanel.getPreferredFocusedComponent();
- }
-
- public JComponent getComponent() {
- return myPanel;
- }
-
-
- public void updateDataModel() {
- final Sdk sdk = getSdk();
- mySettingsHolder.setSdk(sdk);
- }
-
- @Nullable
- private Sdk getSdk() {
- return myPanel.getChosenJdk();
- }
-
- public boolean validate() {
- return true;
- }
-}
diff --git a/python/psi-api/python-psi-api.iml b/python/psi-api/python-psi-api.iml
index e64340e..cbd0718 100644
--- a/python/psi-api/python-psi-api.iml
+++ b/python/psi-api/python-psi-api.iml
@@ -4,7 +4,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
- <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
diff --git a/python/psi-api/src/com/jetbrains/python/FunctionParameter.java b/python/psi-api/src/com/jetbrains/python/FunctionParameter.java
index bceba9e..622a092 100644
--- a/python/psi-api/src/com/jetbrains/python/FunctionParameter.java
+++ b/python/psi-api/src/com/jetbrains/python/FunctionParameter.java
@@ -9,7 +9,13 @@
*/
public interface FunctionParameter {
/**
- * @return parameter position
+ * Position value if argument is keyword-only
+ */
+ int POSITION_NOT_SUPPORTED = -1;
+
+ /**
+ * @return parameter position. Be sure to check position is supported (!= {@link #POSITION_NOT_SUPPORTED} )
+ * @see #POSITION_NOT_SUPPORTED
*/
int getPosition();
diff --git a/python/psi-api/src/com/jetbrains/python/nameResolver/FQNamesProvider.java b/python/psi-api/src/com/jetbrains/python/nameResolver/FQNamesProvider.java
index 1874f3b..c8c80f4 100644
--- a/python/psi-api/src/com/jetbrains/python/nameResolver/FQNamesProvider.java
+++ b/python/psi-api/src/com/jetbrains/python/nameResolver/FQNamesProvider.java
@@ -12,4 +12,9 @@
*/
@NotNull
String[] getNames();
+
+ /**
+ * @return is name of class (true) or function (false)
+ */
+ boolean isClass();
}
diff --git a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java
index aaf3276..e8d8f51 100644
--- a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java
+++ b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java
@@ -2,14 +2,13 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
+import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyQualifiedNameOwner;
import org.jetbrains.annotations.NotNull;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
/**
* @author Ilya.Kazakevich
@@ -52,25 +51,28 @@
elementToCheck = (PyElement)resolvedElement;
}
}
+ String qualifiedName = null;
if (elementToCheck instanceof PyQualifiedNameOwner) {
- final String qualifiedName = ((PyQualifiedNameOwner)elementToCheck).getQualifiedName();
- return getNames(namesProviders).contains(qualifiedName);
+ qualifiedName = ((PyQualifiedNameOwner)elementToCheck).getQualifiedName();
+ }
+ String className = null;
+ if (elementToCheck instanceof PyFunction) {
+ final PyClass aClass = ((PyFunction)elementToCheck).getContainingClass();
+ if (aClass != null) {
+ className = aClass.getQualifiedName();
+ }
+ }
+
+ for (final FQNamesProvider provider : namesProviders) {
+ final List<String> names = Arrays.asList(provider.getNames());
+ if (qualifiedName != null && names.contains(qualifiedName)) {
+ return true;
+ }
+ if (className != null && provider.isClass() && names.contains(className)) {
+ return true;
+ }
}
return false;
}
- /**
- * Returns set of names all providers provide
- *
- * @param providers providers to check
- * @return set of names
- */
- @NotNull
- private static Collection<String> getNames(@NotNull final FQNamesProvider... providers) {
- final Set<String> result = new HashSet<String>();
- for (final FQNamesProvider provider : providers) {
- result.addAll(Arrays.asList(provider.getNames()));
- }
- return result;
- }
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
index 07dcc0fb..581c425 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
+import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import org.jetbrains.annotations.NotNull;
@@ -66,6 +67,16 @@
@Nullable
<T extends PsiElement> T getArgument(int index, String keyword, Class<T> argClass);
+ /**
+ * Returns the argument if one is present in the list.
+ *
+ * @param parameter parameter
+ * @param argClass argument expected type
+ * @return the argument or null
+ */
+ @Nullable
+ <T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull Class<T> argClass);
+
@Nullable
PyExpression getKeywordArgument(String keyword);
diff --git a/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java b/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java
index e8fa271..0359855 100644
--- a/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java
+++ b/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java
@@ -43,7 +43,7 @@
more = false;
errorContents = str;
}
- return new Pair<String, Boolean>(errorContents, more);
+ return Pair.create(errorContents, more);
}
@Override
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
index 4bca6e7..a307c03 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
@@ -481,13 +481,16 @@
}
case AbstractCommand.SUSPEND_THREAD: {
final PyThreadInfo event = parseThreadEvent(frame);
- final PyThreadInfo thread = myThreads.get(event.getId());
- if (thread != null) {
- thread.updateState(PyThreadInfo.State.SUSPENDED, event.getFrames());
- thread.setStopReason(event.getStopReason());
- thread.setMessage(event.getMessage());
- myDebugProcess.threadSuspended(thread);
+ PyThreadInfo thread = myThreads.get(event.getId());
+ if (thread == null) {
+ LOG.error("Trying to stop on non-existent thread: " + event.getId() + ", " + event.getStopReason() + ", " + event.getMessage());
+ myThreads.put(event.getId(), event);
+ thread = event;
}
+ thread.updateState(PyThreadInfo.State.SUSPENDED, event.getFrames());
+ thread.setStopReason(event.getStopReason());
+ thread.setMessage(event.getMessage());
+ myDebugProcess.threadSuspended(thread);
break;
}
case AbstractCommand.RESUME_THREAD: {
diff --git a/python/python-community.iml b/python/python-community.iml
index 06515d2..831f4bd 100644
--- a/python/python-community.iml
+++ b/python/python-community.iml
@@ -4,7 +4,8 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
- <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
diff --git a/python/python-rest/python-rest.iml b/python/python-rest/python-rest.iml
index 5360629..56389c1 100644
--- a/python/python-rest/python-rest.iml
+++ b/python/python-rest/python-rest.iml
@@ -4,7 +4,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
- <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
diff --git a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
index 4a9caf6..52b8de6 100644
--- a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
+++ b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
@@ -18,19 +18,16 @@
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.util.SystemInfo;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.sdk.PythonSdkType;
-import org.jetbrains.annotations.Nullable;
/**
* User : catherine
@@ -54,8 +51,7 @@
PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
try {
final PyPackage sphinx = manager.findPackage("Sphinx");
- String quickStart = findQuickStart(sdk);
- presentation.setEnabled(sphinx != null && quickStart != null);
+ presentation.setEnabled(sphinx != null);
}
catch (PyExternalProcessException ignored) {
}
@@ -64,10 +60,4 @@
}
return presentation;
}
-
- @Nullable
- public static String findQuickStart(final Sdk sdkHome) {
- final String runnerName = "sphinx-quickstart" + (SystemInfo.isWindows ? ".exe" : "");
- return PythonSdkType.getExecutablePath(sdkHome, runnerName);
- }
}
diff --git a/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java b/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java
index 48a20df..67c5809 100644
--- a/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java
+++ b/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java
@@ -22,7 +22,6 @@
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
-import com.jetbrains.rest.RestPythonUtil;
import com.jetbrains.rest.RestTokenTypes;
import com.jetbrains.rest.RestUtil;
import com.jetbrains.rest.psi.RestReferenceTarget;
@@ -48,11 +47,8 @@
@NotNull CompletionResultSet result) {
Sdk sdk = ProjectRootManager.getInstance(parameters.getPosition().getProject()).getProjectSdk();
if (sdk != null) {
- String sphinx = RestPythonUtil.findQuickStart(sdk);
- if (sphinx != null) {
- for (String tag : RestUtil.SPHINX_DIRECTIVES) {
- result.addElement(LookupElementBuilder.create(tag));
- }
+ for (String tag : RestUtil.SPHINX_DIRECTIVES) {
+ result.addElement(LookupElementBuilder.create(tag));
}
}
}
diff --git a/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java b/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
index b849255..9bcd63c 100644
--- a/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
+++ b/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
@@ -21,8 +21,6 @@
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -34,7 +32,10 @@
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.ReSTService;
import com.jetbrains.python.psi.*;
-import com.jetbrains.rest.*;
+import com.jetbrains.rest.RestBundle;
+import com.jetbrains.rest.RestFile;
+import com.jetbrains.rest.RestTokenTypes;
+import com.jetbrains.rest.RestUtil;
import com.jetbrains.rest.psi.RestDirectiveBlock;
import com.jetbrains.rest.psi.RestRole;
import com.jetbrains.rest.quickfixes.AddIgnoredRoleFix;
@@ -96,17 +97,15 @@
for (PyFunction function : functions) {
if (!"setup".equals(function.getName())) continue;
PyStatementList stList = function.getStatementList();
- if (stList != null) {
- PyStatement[] statements = stList.getStatements();
- for (PyElement statement : statements) {
- if (statement instanceof PyExpressionStatement)
- statement = ((PyExpressionStatement)statement).getExpression();
- if (statement instanceof PyCallExpression) {
- if (((PyCallExpression)statement).isCalleeText("add_role")) {
- PyExpression arg = ((PyCallExpression)statement).getArguments()[0];
- if (arg instanceof PyStringLiteralExpression)
- mySphinxRoles.add(((PyStringLiteralExpression)arg).getStringValue());
- }
+ PyStatement[] statements = stList.getStatements();
+ for (PyElement statement : statements) {
+ if (statement instanceof PyExpressionStatement)
+ statement = ((PyExpressionStatement)statement).getExpression();
+ if (statement instanceof PyCallExpression) {
+ if (((PyCallExpression)statement).isCalleeText("add_role")) {
+ PyExpression arg = ((PyCallExpression)statement).getArguments()[0];
+ if (arg instanceof PyStringLiteralExpression)
+ mySphinxRoles.add(((PyStringLiteralExpression)arg).getStringValue());
}
}
}
@@ -124,14 +123,8 @@
if (RestUtil.PREDEFINED_ROLES.contains(node.getText()) || myIgnoredRoles.contains(node.getRoleName()))
return;
- Sdk sdk = ProjectRootManager.getInstance(node.getProject()).getProjectSdk();
- if (sdk != null) {
- String sphinx = RestPythonUtil.findQuickStart(sdk);
- if (sphinx != null) {
- if (RestUtil.SPHINX_ROLES.contains(node.getText()) || RestUtil.SPHINX_ROLES.contains(":py"+node.getText())
- || mySphinxRoles.contains(node.getRoleName())) return;
- }
- }
+ if (RestUtil.SPHINX_ROLES.contains(node.getText()) || RestUtil.SPHINX_ROLES.contains(":py"+node.getText())
+ || mySphinxRoles.contains(node.getRoleName())) return;
Set<String> definedRoles = new HashSet<String>();
diff --git a/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java b/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
index d688544..ee0d0e5 100644
--- a/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
+++ b/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
@@ -31,13 +31,13 @@
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.ReSTService;
import com.jetbrains.python.buildout.BuildoutFacet;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.run.PythonProcessRunner;
import com.jetbrains.python.run.PythonTracebackFilter;
import com.jetbrains.python.sdk.PythonSdkType;
-import com.jetbrains.rest.RestPythonUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -152,17 +152,20 @@
ParamsGroup script_params = cmd.getParametersList().getParamsGroup(PythonCommandLineState.GROUP_SCRIPT);
assert script_params != null;
- String commandPath = getCommandPath(sdk);
+ String commandPath = PythonHelpersLocator.getHelperPath("pycharm/pycharm_load_entry_point.py");
if (commandPath == null) {
throw new ExecutionException("Cannot find sphinx-quickstart.");
}
- cmd.setExePath(commandPath);
-
+ final String sdkHomePath = sdk.getHomePath();
+ if (sdkHomePath != null)
+ cmd.setExePath(sdkHomePath);
+ cmd.addParameter(commandPath);
if (params != null) {
for (String p : params) {
script_params.addParameter(p);
}
}
+ cmd.addParameters("Sphinx", "sphinx-quickstart");
cmd.setPassParentEnvironment(true);
setPythonIOEncoding(cmd.getEnvironment(), "utf-8");
@@ -171,9 +174,9 @@
List<String> pathList = Lists.newArrayList(PythonCommandLineState.getAddedPaths(sdk));
pathList.addAll(PythonCommandLineState.collectPythonPath(module));
- PythonCommandLineState.initPythonPath(cmd, true, pathList, sdk.getHomePath());
+ PythonCommandLineState.initPythonPath(cmd, true, pathList, sdkHomePath);
- PythonSdkType.patchCommandLineForVirtualenv(cmd, sdk.getHomePath(), true);
+ PythonSdkType.patchCommandLineForVirtualenv(cmd, sdkHomePath, true);
BuildoutFacet facet = BuildoutFacet.getInstance(module);
if (facet != null) {
facet.patchCommandLineForBuildout(cmd);
@@ -182,8 +185,4 @@
return cmd;
}
- @Nullable
- private static String getCommandPath(Sdk sdk) {
- return RestPythonUtil.findQuickStart(sdk);
- }
}
diff --git a/python/resources/pycharm_core_about.png b/python/resources/pycharm_core_about.png
index b9fa97f..6e92309 100644
--- a/python/resources/pycharm_core_about.png
+++ b/python/resources/pycharm_core_about.png
Binary files differ
diff --git a/python/resources/[email protected] b/python/resources/[email protected]
index c58e5a3..a831870 100644
--- a/python/resources/[email protected]
+++ b/python/resources/[email protected]
Binary files differ
diff --git a/python/resources/pycharm_core_logo.png b/python/resources/pycharm_core_logo.png
index aa19d19..3daabba 100644
--- a/python/resources/pycharm_core_logo.png
+++ b/python/resources/pycharm_core_logo.png
Binary files differ
diff --git a/python/resources/[email protected] b/python/resources/[email protected]
index 97912f54..83bf65b 100644
--- a/python/resources/[email protected]
+++ b/python/resources/[email protected]
Binary files differ
diff --git a/python/resources/tips/CtrlW.html b/python/resources/tips/CtrlW.html
index b4e609c..34e3054 100644
--- a/python/resources/tips/CtrlW.html
+++ b/python/resources/tips/CtrlW.html
@@ -5,7 +5,7 @@
<body>
- <p><span class="shortcut">&shortcut:EditorSelectWord;</span> (select word) in the editor selects the word at the caret
+ <p><span class="shortcut">&shortcut:EditorSelectWord;</span> (extend selection) in the editor selects the word at the caret
and then selects expanding areas of the source code. For example, it may select a method name,
then the expression that calls this method, then the whole statement, then the containing block, etc.
You can also select the word at the caret and the expanding areas of the source code by double-clicking the target areas in the editor. </p>
diff --git a/python/rest/src/com/jetbrains/rest/lexer/_RestFlexLexer.java b/python/rest/gen/com/jetbrains/rest/lexer/_RestFlexLexer.java
similarity index 99%
rename from python/rest/src/com/jetbrains/rest/lexer/_RestFlexLexer.java
rename to python/rest/gen/com/jetbrains/rest/lexer/_RestFlexLexer.java
index 8c3a1de..8fa7e54 100644
--- a/python/rest/src/com/jetbrains/rest/lexer/_RestFlexLexer.java
+++ b/python/rest/gen/com/jetbrains/rest/lexer/_RestFlexLexer.java
@@ -1,4 +1,4 @@
-/* The following code was generated by JFlex 1.4.3 on 12/17/13 7:08 PM */
+/* The following code was generated by JFlex 1.4.3 on 4/26/14 12:40 PM */
package com.jetbrains.rest.lexer;
@@ -11,8 +11,8 @@
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
- * on 12/17/13 7:08 PM from the specification file
- * <tt>/home/ktisha/IDEA/tools/lexer/../../community/python/rest/src/com/jetbrains/rest/lexer/rest.flex</tt>
+ * on 4/26/14 12:40 PM from the specification file
+ * <tt>/Users/ignatov/src/ultimate/tools/lexer/../../community/python/rest/src/com/jetbrains/rest/lexer/rest.flex</tt>
*/
public class _RestFlexLexer implements FlexLexer, RestTokenTypes {
/** initial size of the lookahead buffer */
diff --git a/python/rest/src/icons/RestIcons.java b/python/rest/gen/icons/RestIcons.java
similarity index 100%
rename from python/rest/src/icons/RestIcons.java
rename to python/rest/gen/icons/RestIcons.java
diff --git a/python/rest/rest.iml b/python/rest/rest.iml
index b9ccb2c..a5d5252 100644
--- a/python/rest/rest.iml
+++ b/python/rest/rest.iml
@@ -4,7 +4,8 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
- <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml
index 2076abd..fdec83a 100644
--- a/python/src/META-INF/pycharm-core.xml
+++ b/python/src/META-INF/pycharm-core.xml
@@ -71,6 +71,7 @@
<bundledColorScheme path="/colorSchemes/monokai"/>
<bundledColorScheme path="/colorSchemes/twilight"/>
<bundledColorScheme path="/colorSchemes/WarmNeon"/>
+ <bundledColorScheme path="/colorSchemes/github"/>
<renameHandler implementation="com.intellij.platform.renameProject.RenameProjectHandler"/>
<renameHandler implementation="com.intellij.platform.renameProject.ProjectFolderRenameHandler"/>
@@ -79,7 +80,6 @@
<actions>
<group id="PlatformOpenProjectGroup">
<action id="NewDirectoryProject" class="com.jetbrains.python.newProject.PythonNewDirectoryProjectAction"/>
- <action id="OpenDirectoryProject" class="com.intellij.platform.OpenDirectoryProjectAction"/>
<add-to-group group-id="FileOpenGroup" anchor="first"/>
</group>
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index c15dcce..dd93341 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -6,7 +6,8 @@
<module value="com.intellij.modules.python"/>
<extensions defaultExtensionNs="com.intellij">
- <targetElement implementation="com.jetbrains.python.magicLiteral.PyMagicTargetElementExtensionPoint"/>
+ <library.type implementation="com.jetbrains.python.library.PythonLibraryType"/>
+ <renameHandler implementation="com.jetbrains.python.magicLiteral.PyMagicLiteralRenameHandler"/>
<nameSuggestionProvider implementation="com.jetbrains.python.refactoring.PyNameSuggestionProvider"/>
<methodNavigationOffsetProvider implementation="com.jetbrains.python.codeInsight.PyMethodNavigationOffsetProvider"/>
<copyPastePreProcessor implementation="com.jetbrains.python.editor.PythonCopyPasteProcessor"/>
diff --git a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
index e5e607a..0ba5e79 100644
--- a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
+++ b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
@@ -365,10 +365,10 @@
return;
}
final List<String> paths = facet.getConfiguration().getPaths();
- FacetLibraryConfigurator.attachLibrary(module, null, BUILDOUT_LIB_NAME, paths);
+ FacetLibraryConfigurator.attachPythonLibrary(module, null, BUILDOUT_LIB_NAME, paths);
}
public static void detachLibrary(final Module module) {
- FacetLibraryConfigurator.detachLibrary(module, BUILDOUT_LIB_NAME);
+ FacetLibraryConfigurator.detachPythonLibrary(module, BUILDOUT_LIB_NAME);
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java
index ba85217..1fac969 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
@Nullable
@Override
- public PsiElement getElementByReference(PsiReference ref, int flags) {
+ public PsiElement getElementByReference(@NotNull PsiReference ref, int flags) {
if ((flags & TargetElementUtilBase.ELEMENT_NAME_ACCEPTED) == 0){
return null;
}
diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
index 17b5f5b..65cd5e1 100644
--- a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
+++ b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
@@ -47,11 +47,13 @@
final Document document = editor.getDocument();
final int lineNumber = document.getLineNumber(offset);
int start = getLineStartSafeOffset(document, lineNumber);
- int end = document.getLineEndOffset(lineNumber) - 1;
+ final int lineEndOffset = document.getLineEndOffset(lineNumber);
+ int end = lineEndOffset == 0 ? 0 : lineEndOffset - 1;
if (selectionModel.hasSelection()) {
start = selectionModel.getSelectionStart();
- end = selectionModel.getSelectionEnd() - 1;
+ final int selectionEnd = selectionModel.getSelectionEnd();
+ end = selectionEnd == 0 ? 0 : selectionEnd - 1;
}
PsiElement elementToMove1 = PyUtil.findNonWhitespaceAtOffset(file, start);
PsiElement elementToMove2 = PyUtil.findNonWhitespaceAtOffset(file, end);
@@ -137,7 +139,7 @@
final PyElement scope = statementList == null ? (PyElement)elementToMove.getContainingFile() : statementList;
if ((elementToMove instanceof PyClass) || (elementToMove instanceof PyFunction))
- return new ScopeRange(scope, null, !down, true);
+ return new ScopeRange(scope, scope.getFirstChild(), !down, true);
return new LineRange(startLine, endLine + 1);
}
@@ -189,7 +191,7 @@
else {
PsiElement scope = getScopeForComment(elementToMove, editor, parent, !down);
PsiElement anchor = PsiTreeUtil.getParentOfType(statementList, PyStatement.class);
- return scope == null ? null : new ScopeRange(scope, anchor, addBefore);
+ return scope == null || anchor == null ? null : new ScopeRange(scope, anchor, addBefore);
}
}
@@ -241,7 +243,7 @@
}
if (statementList2 != null && scopeForComment != statementList2 &&
- (statementList2.getLastChild() == element || statementList2.getLastChild() == elementToMove)) {
+ (statementList2.getLastChild() == element || statementList2.getLastChild() == elementToMove) && element != null) {
return new ScopeRange(statementList2, element, false);
}
return null;
@@ -501,7 +503,7 @@
}
}
else {
- if (startElement != endElement) {
+ if (startElement != endElement && nextSibling != null) {
scope.addRangeAfter(nextSibling, endElement, anchor);
}
addedElement = scope.addAfter(startElement, anchor);
@@ -629,18 +631,18 @@
// Use when element scope changed
static class ScopeRange extends LineRange {
private PsiElement myScope;
- private PsiElement myAnchor;
+ @NotNull private PsiElement myAnchor;
private boolean addBefore;
private boolean theSameLevel;
- public ScopeRange(@NotNull PsiElement scope, @Nullable PsiElement anchor, boolean before) {
+ public ScopeRange(@NotNull PsiElement scope, @NotNull PsiElement anchor, boolean before) {
super(scope);
myScope = scope;
myAnchor = anchor;
addBefore = before;
}
- public ScopeRange(PyElement scope, PsiElement anchor, boolean before, boolean b) {
+ public ScopeRange(PyElement scope, @NotNull PsiElement anchor, boolean before, boolean b) {
super(scope);
myScope = scope;
myAnchor = anchor;
@@ -648,6 +650,7 @@
theSameLevel = b;
}
+ @NotNull
public PsiElement getAnchor() {
return myAnchor;
}
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java
index e183aae..3df0a3e 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -316,6 +316,6 @@
if (seeker != null && seeker instanceof PsiWhiteSpace) sb.append(seeker.getText());
else break;
}
- return new Pair<String, PsiElement>(sb.toString(), seeker);
+ return Pair.create(sb.toString(), seeker);
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java
index d34fc1f..a4d4e9c 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java
@@ -25,6 +25,8 @@
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.Stack;
import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PythonStringUtil;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -72,8 +74,20 @@
if (((PyNamedParameter)parameter).isKeywordContainer()) {
List <PySubscriptionExpression> subscriptions = fillSubscriptions(function);
List <PyCallExpression> callElements = fillCallExpressions(function);
- if ((subscriptions.size() + callElements.size()) != 0)
- return true;
+ if ((subscriptions.size() + callElements.size()) != 0) {
+ for (PyCallExpression element : callElements) {
+ final PyExpression[] arguments = element.getArguments();
+ if (arguments.length < 1) return false;
+ if (!PyNames.isIdentifierString(PythonStringUtil.getStringValue(arguments[0])))
+ return false;
+ }
+ for (PySubscriptionExpression subscription : subscriptions) {
+ final PyExpression expression = subscription.getIndexExpression();
+ if (!PyNames.isIdentifierString(PythonStringUtil.getStringValue(expression)))
+ return false;
+ }
+ }
+ return true;
}
}
}
@@ -112,7 +126,7 @@
PyStatementList statementList = function.getStatementList();
Stack<PsiElement> stack = new Stack<PsiElement>();
PyParameter keywordContainer = getKeywordContainer(function);
- if (keywordContainer != null && statementList != null) {
+ if (keywordContainer != null) {
String keywordContainerName = keywordContainer.getName();
for (PyStatement st : statementList.getStatements()) {
stack.push(st);
@@ -146,7 +160,7 @@
PyStatementList statementList = function.getStatementList();
Stack<PsiElement> stack = new Stack<PsiElement>();
PyParameter keywordContainer = getKeywordContainer(function);
- if (keywordContainer != null && statementList != null) {
+ if (keywordContainer != null) {
String keywordContainerName = keywordContainer.getName();
for (PyStatement st : statementList.getStatements()) {
stack.push(st);
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/DeclarationConflictChecker.java b/python/src/com/jetbrains/python/codeInsight/intentions/DeclarationConflictChecker.java
index 1eb1730..cac318d 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/DeclarationConflictChecker.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/DeclarationConflictChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@
if (ignored != null) for (PsiElement ignorable : ignored) {
if (result == ignorable) continue REF_LOOP;
}
- conflicts.add(new Pair<PsiElement, PsiElement>(ref.getElement(), result));
+ conflicts.add(Pair.create(ref.getElement(), result));
}
}
return conflicts;
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java
index c2624aa..f4fd792 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -134,7 +134,7 @@
NotNullFunction<String,String> escaper = StringUtil.escaper(false, "\"\'\\");
StringBuilder stringLiteral = new StringBuilder();
List<String> parameters = new ArrayList<String>();
- Pair<String, String> quotes = new Pair<String, String>("\"", "\"");
+ Pair<String, String> quotes = Pair.create("\"", "\"");
boolean quotesDetected = false;
final TypeEvalContext context = TypeEvalContext.userInitiated(file);
int paramCount = 0;
@@ -163,7 +163,7 @@
}
}
if (quotes == null)
- quotes = new Pair<String, String>("\"", "\"");
+ quotes = Pair.create("\"", "\"");
stringLiteral.insert(0, quotes.getFirst());
if (isUnicode && !quotes.getFirst().toLowerCase().contains("u"))
stringLiteral.insert(0, "u");
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java
index 4cbaf2b..d014be4 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java
@@ -53,7 +53,7 @@
if (expression == null) {
return false;
}
-
+ if (expression.getComponents().isEmpty()) return false;
PsiElement parent = expression.getParent();
if (parent instanceof PyAssignmentStatement || parent instanceof PyPrintStatement) {
return true;
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java
index d0fb667..6165e81 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java
@@ -63,15 +63,13 @@
PyExpression problemElement = PsiTreeUtil.getParentOfType(elementAt, PyReferenceExpression.class);
if (problemElement == null) return false;
if (problemElement.getParent() instanceof PyWithItem) return false;
- if (problemElement instanceof PyQualifiedExpression) {
- final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
- if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) {
- problemElement = qualifier;
- }
+ final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
+ if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) {
+ problemElement = qualifier;
}
final PsiReference reference = problemElement.getReference();
if (problemElement.getParent() instanceof PyCallExpression ||
- PsiTreeUtil.getParentOfType(problemElement, PyListCompExpression.class) != null ||
+ PsiTreeUtil.getParentOfType(problemElement, PyComprehensionElement.class) != null ||
PsiTreeUtil.getParentOfType(problemElement, PyLambdaExpression.class) != null ||
PsiTreeUtil.getParentOfType(problemElement, PyGeneratorExpression.class) != null ||
(reference != null && reference.resolve() == null)) {
@@ -88,13 +86,11 @@
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
String name = problemElement.getText();
- if (problemElement instanceof PyQualifiedExpression) {
- final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
- if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) {
- final String referencedName = ((PyQualifiedExpression)problemElement).getReferencedName();
- if (referencedName == null || PyNames.GETITEM.equals(referencedName))
- name = qualifier.getText();
- }
+ final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
+ if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) {
+ final String referencedName = ((PyQualifiedExpression)problemElement).getReferencedName();
+ if (referencedName == null || PyNames.GETITEM.equals(referencedName))
+ name = qualifier.getText();
}
final String text = "assert isinstance(" + name + ", )";
@@ -115,7 +111,7 @@
if (statementList != null) {
PsiElement statementListParent = PsiTreeUtil.getParentOfType(statementList, PyStatement.class);
- if (document.getLineNumber(statementList.getTextOffset()) ==
+ if (statementListParent != null && document.getLineNumber(statementList.getTextOffset()) ==
document.getLineNumber(statementListParent.getTextOffset())) {
final String substring =
TextRange.create(statementListParent.getTextRange().getStartOffset(), statementList.getTextOffset()).substring(document.getText());
@@ -125,6 +121,7 @@
statementListParent = statementListParent.replace(foo);
statementList = PsiTreeUtil.findChildOfType(statementListParent, PyStatementList.class);
+ assert statementList != null;
element = statementList.getStatements()[0];
}
else
diff --git a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
index 3fd5a07..8cb83a8 100644
--- a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
+++ b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
@@ -33,7 +33,8 @@
public static final IFileElementType PYTHON_REGEXP_FILE = new IFileElementType("PYTHON_REGEXP_FILE", PythonRegexpLanguage.INSTANCE);
protected final EnumSet<RegExpCapability> CAPABILITIES = EnumSet.of(RegExpCapability.DANGLING_METACHARACTERS,
RegExpCapability.OCTAL_NO_LEADING_ZERO,
- RegExpCapability.OMIT_NUMBERS_IN_QUANTIFIERS);
+ RegExpCapability.OMIT_NUMBERS_IN_QUANTIFIERS,
+ RegExpCapability.ALLOW_EMPTY_CHARACTER_CLASS);
@NotNull
public Lexer createLexer(Project project) {
diff --git a/python/src/com/jetbrains/python/console/PyConsoleDebugProcess.java b/python/src/com/jetbrains/python/console/PyConsoleDebugProcess.java
new file mode 100644
index 0000000..616dc7c
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PyConsoleDebugProcess.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.execution.ui.ExecutionConsole;
+import com.intellij.remote.RemoteProcessHandlerBase;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.XDebugSession;
+import com.jetbrains.python.debugger.PyDebugProcess;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.ServerSocket;
+
+/**
+ * @author traff
+ */
+public class PyConsoleDebugProcess extends PyDebugProcess {
+ private final int myLocalPort;
+ private final PyConsoleDebugProcessHandler myConsoleDebugProcessHandler;
+
+ public PyConsoleDebugProcess(@NotNull XDebugSession session,
+ @NotNull final ServerSocket serverSocket,
+ @NotNull final ExecutionConsole executionConsole,
+ @NotNull final PyConsoleDebugProcessHandler consoleDebugProcessHandler) {
+ super(session, serverSocket, executionConsole, consoleDebugProcessHandler, false);
+ myLocalPort = serverSocket.getLocalPort();
+ myConsoleDebugProcessHandler = consoleDebugProcessHandler;
+ }
+
+ @Override
+ public void sessionInitialized() {
+ //nop
+ }
+
+ @Override
+ protected String getConnectionMessage() {
+ return "Connecting to console...";
+ }
+
+ @Override
+ protected String getConnectionTitle() {
+ return "Debugger connection";
+ }
+
+ @Override
+ protected void detachDebuggedProcess() {
+ //TODO: implement disconnect
+ }
+
+ @Override
+ protected void beforeConnect() {
+ printToConsole(getCurrentStateMessage() + "\n", ConsoleViewContentType.SYSTEM_OUTPUT);
+ }
+
+ @Override
+ protected void afterConnect() {
+ }
+
+
+ @Override
+ public int getConnectTimeout() {
+ return 0; //server should not stop
+ }
+
+ public void connect(PydevConsoleCommunication consoleCommunication) throws Exception {
+ int portToConnect;
+ if (myConsoleDebugProcessHandler.getConsoleProcessHandler() instanceof RemoteProcessHandlerBase) {
+ portToConnect = getRemoteTunneledPort(myLocalPort,
+ ((RemoteProcessHandlerBase)myConsoleDebugProcessHandler.getConsoleProcessHandler()));
+ } else {
+ portToConnect = myLocalPort;
+ }
+ consoleCommunication.connectToDebugger(portToConnect);
+ }
+
+ public void waitForNextConnection() {
+ if (isConnected()) {
+ disconnect();
+ }
+ if (getSession().isSuspended()) {
+ getSession().resume();
+ }
+ if (!isWaitingForConnection()) {
+ setWaitingForConnection(true);
+
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ waitForConnection(getCurrentStateMessage(), getConnectionTitle());
+ }
+ });
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/PyConsoleDebugProcessHandler.java b/python/src/com/jetbrains/python/console/PyConsoleDebugProcessHandler.java
new file mode 100644
index 0000000..9399bca
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PyConsoleDebugProcessHandler.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.intellij.execution.process.*;
+import com.intellij.openapi.util.Key;
+import com.jetbrains.python.debugger.PositionConverterProvider;
+import com.jetbrains.python.debugger.PyDebugProcess;
+import com.jetbrains.python.debugger.PyLocalPositionConverter;
+import com.jetbrains.python.debugger.PyPositionConverter;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.OutputStream;
+
+/**
+ * @author traff
+ */
+public class PyConsoleDebugProcessHandler extends ProcessHandler implements PositionConverterProvider {
+ private final PyConsoleProcessHandler myConsoleProcessHandler;
+
+ public PyConsoleDebugProcessHandler(final PyConsoleProcessHandler processHandler) {
+ myConsoleProcessHandler = processHandler;
+ processHandler.addProcessListener(new ProcessListener() {
+ @Override
+ public void startNotified(ProcessEvent event) {
+
+ }
+
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ PyConsoleDebugProcessHandler.this.notifyProcessTerminated(event.getExitCode());
+ }
+
+ @Override
+ public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
+
+ }
+
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ }
+ });
+
+ processHandler.addColoredTextListener(new AnsiEscapeDecoder.ColoredTextAcceptor() {
+ @Override
+ public void coloredTextAvailable(String text, Key attributes) {
+ PyConsoleDebugProcessHandler.this.notifyTextAvailable(text, attributes);
+ }
+ });
+ }
+
+ @Override
+ protected void destroyProcessImpl() {
+ detachProcessImpl();
+ }
+
+ @Override
+ protected void detachProcessImpl() {
+ notifyProcessTerminated(0);
+ notifyTextAvailable("Debugger disconnected.\n", ProcessOutputTypes.SYSTEM);
+ }
+
+ @Override
+ public boolean detachIsDefault() {
+ return false;
+ }
+
+ @Override
+ public OutputStream getProcessInput() {
+ return null;
+ }
+
+ public PyConsoleProcessHandler getConsoleProcessHandler() {
+ return myConsoleProcessHandler;
+ }
+
+ @Nullable
+ @Override
+ public PyPositionConverter createPositionConverter(PyDebugProcess debugProcess) {
+ if (myConsoleProcessHandler instanceof PositionConverterProvider) {
+ return ((PositionConverterProvider)myConsoleProcessHandler).createPositionConverter(debugProcess);
+ }
+ else {
+ return new PyLocalPositionConverter();
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/PyConsoleIndentUtil.java b/python/src/com/jetbrains/python/console/PyConsoleIndentUtil.java
index 84ca6e8..15136fc 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleIndentUtil.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleIndentUtil.java
@@ -16,13 +16,13 @@
package com.jetbrains.python.console;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
-import java.util.List;
-import java.util.Scanner;
+import java.util.*;
/**
* @author traff
@@ -30,6 +30,12 @@
public class PyConsoleIndentUtil {
private static final int TAB_INDENT = 4;
+ private static final Map<String, String> pythonBrackets = ImmutableMap.of(
+ "(", ")",
+ "[", "]",
+ "{", "}"
+ );
+
private PyConsoleIndentUtil() {
}
@@ -70,66 +76,59 @@
indentArray[i] += addIndent;
}
- shiftToParentOnUnindent(indentArray);
-
return padOutput(lines, indentArray);
}
- private static void shiftToParentOnUnindent(int[] indentArray) {
- int[] stack = new int[indentArray.length];
- int count = 0;
- int replace = -1;
- int replaceBy = -1;
- for (int i = 0; i < indentArray.length; i++) {
- if (indentArray[i] == replace) {
- indentArray[i] = replaceBy;
- }
- else {
- replace = -1;
- if (count == 0 || indentArray[i] > stack[count - 1]) {
- stack[count++] = indentArray[i];
- }
- if (count > 0 && indentArray[i] < stack[count - 1]) {
- do {
- count--;
- }
- while (count > 0 && stack[count - 1] > indentArray[i]);
- if (count > 0) {
- replace = indentArray[i];
- replaceBy = stack[count - 1];
- indentArray[i] = replaceBy;
- }
- }
- }
- }
- }
-
private static void shiftLeftAll(int[] indentArray, List<String> lines) {
if (indentArray.length == 0) {
return;
}
- int indent = indentArray[0];
- int lastIndent = Integer.MAX_VALUE;
- boolean lastIndented = false;
- for (int i = 0; i < indentArray.length; i++) {
- if (!StringUtil.isEmpty(lines.get(i))) {
- if (i > 0 && shouldSkipNext(lines.get(i - 1))) {
- indentArray[i] -= indent;
- continue;
- }
- if (indentArray[i] < indent || indentArray[i] > lastIndent && !lastIndented) {
- indent = indentArray[i];
- }
- lastIndent = indentArray[i];
- indentArray[i] -= indent;
- if (shouldIndent(lines.get(i))) {
- lastIndented = true;
- }
- else {
- lastIndented = false;
- }
+
+ int minpos = arrayMinPosition(indentArray, indentArray.length);
+ if (minpos == 0) {
+ int minIndent = indentArray[minpos];
+ shiftTailLeftOnLevel(indentArray, minIndent);
+ return;
+ }
+
+ int prevMinPosition = indentArray.length;
+ while (minpos != 0) {
+ shiftTailLeftOnLevel(indentArray, minpos, prevMinPosition, indentArray[minpos]);
+ prevMinPosition = minpos;
+ minpos = arrayMinPosition(indentArray, minpos);
+ }
+
+ int minIndent = indentArray[minpos];
+ for (int i = 0; indentArray[i] != 0; i++) {
+ indentArray[i] -= minIndent;
+ }
+ }
+
+ private static void shiftTailLeftOnLevel(int[] indentArray, int level) {
+ shiftTailLeftOnLevel(indentArray, 0, indentArray.length, level);
+ }
+
+ private static void shiftTailLeftOnLevel(int[] indentArray, int upper, int bottom, int level) {
+ for (int i = upper; i < bottom; i++) {
+ if (indentArray[i] < level) {
+ throw new IllegalStateException("Current indentation is less then subtracted level.");
+ }
+ indentArray[i] -= level;
+ }
+ }
+
+ private static int arrayMinPosition(int[] indentArray, int border) {
+ if (border < 1) {
+ return -1;
+ }
+
+ int minPosition = 0;
+ for (int i = 0; i < border; i++) {
+ if (indentArray[minPosition] > indentArray[i]) {
+ minPosition = i;
}
}
+ return minPosition;
}
private static String padOutput(List<String> lines, int[] indentArray) {
@@ -161,9 +160,4 @@
}
return line;
}
-
- public static boolean shouldSkipNext(@NotNull String line) {
- line = stripComments(line);
- return line.endsWith(",");
- }
}
diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptions.java b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
index d02b670..e76c2ae 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleOptions.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
@@ -60,6 +60,13 @@
myState.myShowSeparatorLine = showSeparatorLine;
}
+ public boolean isIpythonEnabled(){
+ return myState.myIpythonEnabled;
+ }
+
+ public void setIpythonEnabled(boolean enabled){
+ myState.myIpythonEnabled = enabled;
+ }
public static PyConsoleOptions getInstance(Project project) {
return ServiceManager.getService(project, PyConsoleOptions.class);
@@ -75,6 +82,7 @@
myState.myShowDebugConsoleByDefault = state.myShowDebugConsoleByDefault;
myState.myShowSeparatorLine = state.myShowSeparatorLine;
myState.myPythonConsoleState = state.myPythonConsoleState;
+ myState.myIpythonEnabled = state.myIpythonEnabled;
}
public static class State {
@@ -82,11 +90,12 @@
public boolean myShowDebugConsoleByDefault = false;
public boolean myShowSeparatorLine = true;
+ public boolean myIpythonEnabled = true;
}
@Tag("console-settings")
public static class PyConsoleSettings {
- public String myCustomStartScript = "";
+ public String myCustomStartScript = RunPythonConsoleAction.CONSOLE_START_COMMAND;
public String mySdkHome = null;
public String myInterpreterOptions = "";
public boolean myUseModuleSdk;
@@ -98,6 +107,13 @@
@NotNull
private PathMappingSettings myMappings = new PathMappingSettings();
+ public PyConsoleSettings(){
+ }
+
+ public PyConsoleSettings(String myCustomStartScript){
+ this.myCustomStartScript = myCustomStartScript;
+ }
+
public void apply(AbstractPyCommonOptionsForm form) {
mySdkHome = form.getSdkHome();
myInterpreterOptions = form.getInterpreterOptions();
diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.form b/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.form
index ed3a719..139d026 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.form
+++ b/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.form
@@ -13,7 +13,7 @@
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
- <grid id="b4377" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="b4377" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -26,7 +26,7 @@
<children>
<component id="d33dd" class="com.intellij.ui.components.JBCheckBox" binding="myShowDebugConsoleByDefault" default-binding="true">
<constraints>
- <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Always show debug console"/>
@@ -34,12 +34,20 @@
</component>
<vspacer id="c732">
<constraints>
- <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
+ <component id="cccd6" class="com.intellij.ui.components.JBCheckBox" binding="myIpythonEnabledCheckbox">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Use IPython if available"/>
+ </properties>
+ </component>
<component id="cc309" class="com.intellij.ui.components.JBCheckBox" binding="myShowSeparatorLine">
<constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Show separator line"/>
diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.java b/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.java
index e658a69..046fc32 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleOptionsConfigurable.java
@@ -173,6 +173,7 @@
private JPanel myWholePanel;
private JBCheckBox myShowDebugConsoleByDefault;
private JBCheckBox myShowSeparatorLine;
+ private JBCheckBox myIpythonEnabledCheckbox;
private PyConsoleOptions myOptionsProvider;
public JPanel createPanel(PyConsoleOptions optionsProvider) {
@@ -184,16 +185,19 @@
public void apply() {
myOptionsProvider.setShowDebugConsoleByDefault(myShowDebugConsoleByDefault.isSelected());
myOptionsProvider.setShowSeparatorLine(myShowSeparatorLine.isSelected());
+ myOptionsProvider.setIpythonEnabled(myIpythonEnabledCheckbox.isSelected());
}
public void reset() {
myShowDebugConsoleByDefault.setSelected(myOptionsProvider.isShowDebugConsoleByDefault());
myShowSeparatorLine.setSelected(myOptionsProvider.isShowSeparatorLine());
+ myIpythonEnabledCheckbox.setSelected(myOptionsProvider.isIpythonEnabled());
}
public boolean isModified() {
return myShowDebugConsoleByDefault.isSelected() != myOptionsProvider.isShowDebugConsoleByDefault() ||
- myShowSeparatorLine.isSelected() != myOptionsProvider.isShowSeparatorLine();
+ myShowSeparatorLine.isSelected() != myOptionsProvider.isShowSeparatorLine() ||
+ myIpythonEnabledCheckbox.isSelected() != myOptionsProvider.isIpythonEnabled();
}
}
diff --git a/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java b/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
index c0c65fc..02b59b3 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
@@ -44,6 +44,8 @@
final String string = PyConsoleUtil.processPrompts(getConsole(), StringUtil.convertLineSeparators(text));
myConsoleView.print(string, attributes);
+
+ notifyColoredListeners(text, attributes);
}
@Override
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
index 6af6c13..9c95b1c 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,6 +63,7 @@
private static final String GET_FRAME = "getFrame";
private static final String GET_VARIABLE = "getVariable";
private static final String CHANGE_VARIABLE = "changeVariable";
+ private static final String CONNECT_TO_DEBUGGER = "connectToDebugger";
private static final String HANDSHAKE = "handshake";
private static final String CLOSE = "close";
@@ -98,6 +99,7 @@
private volatile boolean firstCommWorked = false;
private boolean myExecuting;
+ private PythonDebugConsoleCommunication myDebugCommunication;
/**
* Initializes the xml-rpc communication.
@@ -303,6 +305,10 @@
*/
@NotNull
public List<PydevCompletionVariant> getCompletions(String text, String actTok) throws Exception {
+ if (myDebugCommunication != null && myDebugCommunication.isSuspended()) {
+ return myDebugCommunication.getCompletions(text, actTok);
+ }
+
if (waitingForInput) {
return Collections.emptyList();
}
@@ -315,6 +321,9 @@
* @return the description of the given attribute in the shell
*/
public String getDescription(String text) throws Exception {
+ if (myDebugCommunication != null && myDebugCommunication.isSuspended()) {
+ return myDebugCommunication.getDescription(text);
+ }
if (waitingForInput) {
return "Unable to get description: waiting for input.";
}
@@ -327,6 +336,10 @@
* @param command the command to be executed in the client
*/
public void execInterpreter(final ConsoleCodeFragment command, final Function<InterpreterResponse, Object> onResponseReceived) {
+ if (myDebugCommunication != null && myDebugCommunication.isSuspended()) {
+ myDebugCommunication.execInterpreter(command, onResponseReceived);
+ return; //TODO: handle text input and other cases
+ }
nextResponse = null;
if (waitingForInput) {
inputReceived = command.getText();
@@ -372,7 +385,7 @@
if (commAttempts < MAX_ATTEMPTS) {
commAttempts += 1;
Thread.sleep(250);
- executed = new Pair<String, Boolean>("", executed.second);
+ executed = Pair.create("", executed.second);
}
else {
break;
@@ -515,9 +528,47 @@
}
}
+
+ /**
+ * Request that pydevconsole connect (with pydevd) to the specified port
+ *
+ * @param localPort port for pydevd to connect to.
+ * @throws Exception if connection fails
+ */
+ public void connectToDebugger(int localPort) throws Exception {
+ if (waitingForInput) {
+ throw new Exception("Can't connect debugger now, waiting for input");
+ }
+ Object result = myClient.execute(CONNECT_TO_DEBUGGER, new Object[]{localPort});
+ Exception exception = null;
+ if (result instanceof Vector) {
+ Vector resultarray = (Vector)result;
+ if (resultarray.size() == 1) {
+ if ("connect complete".equals(resultarray.get(0))) {
+ return;
+ }
+ if (resultarray.get(0) instanceof String) {
+ exception = new Exception((String)resultarray.get(0));
+ }
+ if (resultarray.get(0) instanceof Exception) {
+ exception = (Exception)resultarray.get(0);
+ }
+ }
+ }
+ throw new PyDebuggerException("pydevconsole failed to execute connectToDebugger", exception);
+ }
+
private static void checkError(Object ret) throws PyDebuggerException {
if (ret instanceof Object[] && ((Object[])ret).length == 1) {
throw new PyDebuggerException(((Object[])ret)[0].toString());
}
}
+
+ public void setDebugCommunication(PythonDebugConsoleCommunication debugCommunication) {
+ myDebugCommunication = debugCommunication;
+ }
+
+ public PythonDebugConsoleCommunication getDebugCommunication() {
+ return myDebugCommunication;
+ }
}
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
index 33cdd0d..434075f 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
@@ -61,9 +61,9 @@
private int myIpythonInputPromptCount = 1;
public PydevConsoleExecuteActionHandler(LanguageConsoleView consoleView,
- ProcessHandler myProcessHandler,
+ ProcessHandler processHandler,
ConsoleCommunication consoleCommunication) {
- super(myProcessHandler, false);
+ super(processHandler, false);
myConsoleView = consoleView;
myConsoleCommunication = consoleCommunication;
myConsoleCommunication.addCommunicationListener(this);
@@ -266,7 +266,6 @@
}
private void ordinaryPrompt(LanguageConsoleImpl console, Editor currentEditor) {
-
if (!myConsoleCommunication.isExecuting()) {
if (!PyConsoleUtil.ORDINARY_PROMPT.equals(console.getPrompt())) {
console.setPrompt(PyConsoleUtil.ORDINARY_PROMPT);
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
index 970b20b..2213375 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
@@ -51,6 +51,7 @@
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
@@ -69,10 +70,15 @@
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.net.NetUtils;
import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.XDebugProcess;
+import com.intellij.xdebugger.XDebugProcessStarter;
+import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.XDebuggerManager;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.completion.PydevConsoleElement;
import com.jetbrains.python.console.parsing.PythonConsoleData;
import com.jetbrains.python.console.pydev.ConsoleCommunication;
+import com.jetbrains.python.debugger.PyDebugRunner;
import com.jetbrains.python.debugger.PySourcePosition;
import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
import com.jetbrains.python.remote.PyRemoteSdkCredentials;
@@ -82,6 +88,7 @@
import com.jetbrains.python.run.PythonTracebackFilter;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
+import icons.PythonIcons;
import org.apache.xmlrpc.XmlRpcException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -90,6 +97,7 @@
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
+import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.*;
@@ -122,8 +130,6 @@
public static Key<Sdk> CONSOLE_SDK = new Key<Sdk>("PYDEV_CONSOLE_SDK_KEY");
- private static final String PYTHON_ENV_COMMAND = "import sys; print('Python %s on %s' % (sys.version, sys.platform))\n";
-
private static final long APPROPRIATE_TO_WAIT = 60000;
protected PydevConsoleRunner(@NotNull final Project project,
@@ -174,6 +180,8 @@
AnAction showVarsAction = new ShowVarsAction();
toolbarActions.add(showVarsAction);
toolbarActions.add(myHistoryController.getBrowseHistory());
+
+ toolbarActions.add(new ConnectDebuggerAction());
return actions;
}
@@ -357,7 +365,7 @@
remoteProcess.addRemoteTunnel(remotePorts.second, "localhost", myPorts[1]);
- myPydevConsoleCommunication = new PydevConsoleCommunication(getProject(), myPorts[0], remoteProcess, myPorts[1]);
+ myPydevConsoleCommunication = new PydevRemoteConsoleCommunication(getProject(), myPorts[0], remoteProcess, myPorts[1]);
return remoteProcess;
}
catch (Exception e) {
@@ -412,8 +420,29 @@
@Override
protected PyConsoleProcessHandler createProcessHandler(final Process process) {
- myProcessHandler = new PyConsoleProcessHandler(process, getConsoleView(), myPydevConsoleCommunication, myCommandLine,
- CharsetToolkit.UTF8_CHARSET);
+ if (PySdkUtil.isRemote(mySdk)) {
+ PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
+ if (manager != null) {
+ PyRemoteSdkAdditionalDataBase data = (PyRemoteSdkAdditionalDataBase)mySdk.getSdkAdditionalData();
+ assert data != null;
+ try {
+ myProcessHandler =
+ manager.createConsoleProcessHandler(process, data.getRemoteSdkCredentials(), getConsoleView(), myPydevConsoleCommunication,
+ myCommandLine, CharsetToolkit.UTF8_CHARSET,
+ manager.setupMappings(getProject(), data, null));
+ }
+ catch (InterruptedException e) {
+ LOG.error("Error getting remote credentials");
+ }
+ }
+ else {
+ LOG.error("Can't create remote console process handler");
+ }
+ }
+ else {
+ myProcessHandler = new PyConsoleProcessHandler(process, getConsoleView(), myPydevConsoleCommunication, myCommandLine,
+ CharsetToolkit.UTF8_CHARSET);
+ }
return myProcessHandler;
}
@@ -441,8 +470,6 @@
enableConsoleExecuteAction();
- consoleView.executeStatement(PYTHON_ENV_COMMAND, ProcessOutputTypes.SYSTEM);
-
for (String statement : statements2execute) {
consoleView.executeStatement(statement + "\n", ProcessOutputTypes.SYSTEM);
}
@@ -783,4 +810,87 @@
}
}
}
+
+
+ private class ConnectDebuggerAction extends ToggleAction implements DumbAware {
+ private boolean mySelected = false;
+ private XDebugSession mySession = null;
+
+ public ConnectDebuggerAction() {
+ super("Attach Debugger", "Enables tracing of code executed in console", AllIcons.Actions.StartDebugger);
+ }
+
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ return mySelected;
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ if (mySession != null) {
+ e.getPresentation().setEnabled(false);
+ }
+ else {
+ e.getPresentation().setEnabled(true);
+ }
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ mySelected = state;
+
+ if (mySelected) {
+ try {
+ mySession = connectToDebugger();
+ }
+ catch (Exception e1) {
+ LOG.error(e1);
+ Messages.showErrorDialog("Can't connect to debugger", "Error Connecting Debugger");
+ }
+ }
+ else {
+ //TODO: disable debugging
+ }
+ }
+ }
+
+ private XDebugSession connectToDebugger() throws ExecutionException {
+ final ServerSocket serverSocket = PythonCommandLineState.createServerSocket();
+
+ final XDebugSession session = XDebuggerManager.getInstance(getProject()).
+ startSessionAndShowTab("Python Console Debugger", PythonIcons.Python.Python, null, true, new XDebugProcessStarter() {
+ @NotNull
+ public XDebugProcess start(@NotNull final XDebugSession session) {
+ PythonDebugLanguageConsoleView debugConsoleView = new PythonDebugLanguageConsoleView(getProject(), mySdk);
+
+ PyConsoleDebugProcessHandler consoleDebugProcessHandler =
+ new PyConsoleDebugProcessHandler(myProcessHandler);
+
+ PyConsoleDebugProcess consoleDebugProcess =
+ new PyConsoleDebugProcess(session, serverSocket, debugConsoleView,
+ consoleDebugProcessHandler);
+
+ PythonDebugConsoleCommunication communication =
+ PyDebugRunner.initDebugConsoleView(getProject(), consoleDebugProcess, debugConsoleView, consoleDebugProcessHandler);
+
+ myPydevConsoleCommunication.setDebugCommunication(communication);
+ debugConsoleView.attachToProcess(consoleDebugProcessHandler);
+
+ consoleDebugProcess.waitForNextConnection();
+
+ try {
+ consoleDebugProcess.connect(myPydevConsoleCommunication);
+ }
+ catch (Exception e) {
+ LOG.error(e); //TODO
+ }
+
+ myProcessHandler.notifyTextAvailable("\nDebugger connected.\n", ProcessOutputTypes.STDERR);
+
+ return consoleDebugProcess;
+ }
+ });
+
+ return session;
+ }
}
diff --git a/python/src/com/jetbrains/python/console/PydevRemoteConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevRemoteConsoleCommunication.java
new file mode 100644
index 0000000..9e4264f
--- /dev/null
+++ b/python/src/com/jetbrains/python/console/PydevRemoteConsoleCommunication.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.console;
+
+import com.intellij.openapi.project.Project;
+
+/**
+ * @author traff
+ */
+public class PydevRemoteConsoleCommunication extends PydevConsoleCommunication {
+ /**
+ * Initializes the xml-rpc communication.
+ *
+ * @param project
+ * @param port the port where the communication should happen.
+ * @param process this is the process that was spawned (server for the XML-RPC)
+ * @param clientPort
+ * @throws MalformedURLException
+ */
+ public PydevRemoteConsoleCommunication(Project project, int port, Process process, int clientPort)
+ throws Exception {
+ super(project, port, process, clientPort);
+ }
+}
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java
index c052333..699294e 100644
--- a/python/src/com/jetbrains/python/console/PythonConsoleView.java
+++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java
@@ -26,11 +26,13 @@
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.ObservableConsoleView;
+import com.intellij.ide.GeneralSettings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
@@ -59,6 +61,8 @@
import javax.swing.*;
import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
/**
* @author traff
@@ -96,6 +100,8 @@
add(myLanguageConsoleView.getComponent(), BorderLayout.CENTER);
+ addSaveContentFocusListener(getLanguageConsole().getConsoleEditor().getContentComponent());
+
getPythonLanguageConsole().setPrompt(PyConsoleUtil.ORDINARY_PROMPT);
myLanguageConsoleView.setUpdateFoldingsEnabled(false);
myProject = project;
@@ -113,6 +119,20 @@
myExecuteActionHandler = consoleExecuteActionHandler;
}
+ private void addSaveContentFocusListener(JComponent component){
+ component.addFocusListener(new FocusListener() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (GeneralSettings.getInstance().isSaveOnFrameDeactivation()) {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {}
+ });
+ }
+
@Override
public void requestFocus() {
IdeFocusManager.findInstance().requestFocus(getPythonLanguageConsole().getConsoleEditor().getContentComponent(), true);
diff --git a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
index d24a2a8a..da1ac531 100644
--- a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
+++ b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
@@ -102,4 +102,8 @@
public void interrupt() {
throw new UnsupportedOperationException();
}
+
+ public boolean isSuspended() {
+ return myDebugProcess.getSession().isSuspended();
+ }
}
diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
index b89fc94..02a153f 100644
--- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
+++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
@@ -38,18 +38,25 @@
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.sdk.PySdkUtil;
+import com.jetbrains.python.sdk.PythonEnvUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
/**
* @author oleg
*/
public class RunPythonConsoleAction extends AnAction implements DumbAware {
+ public static final String WORKING_DIR_ENV = "WORKING_DIR_AND_PYTHON_PATHS";
+
+ public static final String CONSOLE_START_COMMAND = "import sys; print('Python %s on %s' % (sys.version, sys.platform))\n" +
+ "sys.path.extend([" + WORKING_DIR_ENV + "])\n";
+
public RunPythonConsoleAction() {
super();
getTemplatePresentation().setIcon(PythonIcons.Python.Python);
@@ -96,14 +103,14 @@
pythonPath = mappingSettings.convertToRemote(pythonPath);
}
- String selfPathAppend = constructPythonPathCommand(pythonPath);
+ String customStartScript = settingsProvider == null ? "" : settingsProvider.getCustomStartScript();
- String customStartScript = settingsProvider.getCustomStartScript();
-
- if (customStartScript.trim().length() > 0) {
- selfPathAppend += "\n" + customStartScript.trim();
+ if(customStartScript.trim().length() > 0){
+ customStartScript = "\n" + customStartScript;
}
+ String selfPathAppend = constructPythonPathCommand(pythonPath, customStartScript);
+
String workingDir = settingsProvider.getWorkingDirectory();
if (StringUtil.isEmpty(workingDir)) {
if (module != null && ModuleRootManager.getInstance(module).getContentRoots().length > 0) {
@@ -140,8 +147,12 @@
setupFragment = new String[]{selfPathAppend};
}
+ Map<String, String> envs = Maps.newHashMap(settingsProvider.getEnvs());
+ String ipythonEnabled = PyConsoleOptions.getInstance(project).isIpythonEnabled() ? "True" : "False";
+ envs.put(PythonEnvUtil.IPYTHONENABLE, ipythonEnabled);
+
return PydevConsoleRunner
- .createAndRun(project, sdk, PyConsoleType.PYTHON, workingDir, Maps.newHashMap(settingsProvider.getEnvs()), setupFragment);
+ .createAndRun(project, sdk, PyConsoleType.PYTHON, workingDir, envs, setupFragment);
}
public static PathMappingSettings getMappings(Project project, Sdk sdk) {
@@ -214,7 +225,7 @@
return Pair.create(sdk, module);
}
- public static String constructPythonPathCommand(Collection<String> pythonPath) {
+ public static String constructPythonPathCommand(Collection<String> pythonPath, String command) {
final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function<String, String>() {
@Override
public String apply(String input) {
@@ -222,6 +233,6 @@
}
}));
- return "sys.path.extend([" + path + "])";
+ return command.replace(WORKING_DIR_ENV, path);
}
}
diff --git a/python/src/com/jetbrains/python/debugger/PositionConverterProvider.java b/python/src/com/jetbrains/python/debugger/PositionConverterProvider.java
new file mode 100644
index 0000000..0235002
--- /dev/null
+++ b/python/src/com/jetbrains/python/debugger/PositionConverterProvider.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.debugger;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author traff
+ */
+public interface PositionConverterProvider {
+ @Nullable
+ PyPositionConverter createPositionConverter(PyDebugProcess debugProcess);
+}
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
index 0bae7af..cff49fb 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
@@ -45,7 +45,6 @@
import com.intellij.xdebugger.stepping.XSmartStepIntoHandler;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.pydev.*;
-import com.jetbrains.python.remote.RemoteDebuggableProcessHandler;
import com.jetbrains.python.run.PythonProcessHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -114,8 +113,8 @@
if (myProcessHandler != null) {
myProcessHandler.addProcessListener(this);
}
- if (processHandler instanceof RemoteDebuggableProcessHandler) {
- myPositionConverter = ((RemoteDebuggableProcessHandler)processHandler).createPositionConverter(this);
+ if (processHandler instanceof PositionConverterProvider) {
+ myPositionConverter = ((PositionConverterProvider)processHandler).createPositionConverter(this);
}
else {
myPositionConverter = new PyLocalPositionConverter();
@@ -263,21 +262,24 @@
@Override
public int handleDebugPort(int localPort) throws IOException {
if (myProcessHandler instanceof RemoteProcessHandlerBase) {
- RemoteProcessHandlerBase remoteProcessHandler = (RemoteProcessHandlerBase)myProcessHandler;
- try {
- Pair<String, Integer> remoteSocket = remoteProcessHandler.obtainRemoteSocket();
- remoteProcessHandler.addRemoteForwarding(remoteSocket.getSecond(), localPort);
- return remoteSocket.getSecond();
- }
- catch (Exception e) {
- throw new IOException(e);
- }
+ return getRemoteTunneledPort(localPort, (RemoteProcessHandlerBase)myProcessHandler);
}
else {
return localPort;
}
}
+ protected static int getRemoteTunneledPort(int localPort, @NotNull RemoteProcessHandlerBase handler) throws IOException {
+ try {
+ Pair<String, Integer> remoteSocket = handler.obtainRemoteSocket();
+ handler.addRemoteForwarding(remoteSocket.getSecond(), localPort);
+ return remoteSocket.getSecond();
+ }
+ catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
@Override
public void recordSignature(PySignature signature) {
PySignatureCacheManager.getInstance(getSession().getProject()).recordSignature(myPositionConverter.convertSignature(signature));
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
index 3199200..583641e 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
@@ -123,20 +123,33 @@
@NotNull PyDebugProcess debugProcess) {
ExecutionConsole console = result.getExecutionConsole();
if (console instanceof PythonDebugLanguageConsoleView) {
- PythonConsoleView pythonConsoleView = ((PythonDebugLanguageConsoleView)console).getPydevConsoleView();
- pythonConsoleView.setConsoleCommunication(new PythonDebugConsoleCommunication(project, debugProcess));
-
ProcessHandler processHandler = result.getProcessHandler();
- PydevDebugConsoleExecuteActionHandler consoleExecuteActionHandler = new PydevDebugConsoleExecuteActionHandler(pythonConsoleView,
- processHandler,
- new PythonDebugConsoleCommunication(project, debugProcess));
- pythonConsoleView.setExecutionHandler(consoleExecuteActionHandler);
- debugProcess.getSession().addSessionListener(consoleExecuteActionHandler);
- new LanguageConsoleBuilder(pythonConsoleView).processHandler(processHandler).initActions(consoleExecuteActionHandler, "py");
+ initDebugConsoleView(project, debugProcess, (PythonDebugLanguageConsoleView)console, processHandler);
}
}
+ public static PythonDebugConsoleCommunication initDebugConsoleView(Project project,
+ PyDebugProcess debugProcess,
+ PythonDebugLanguageConsoleView console,
+ ProcessHandler processHandler) {
+ PythonConsoleView pythonConsoleView = console.getPydevConsoleView();
+ PythonDebugConsoleCommunication debugConsoleCommunication = new PythonDebugConsoleCommunication(project, debugProcess);
+
+ pythonConsoleView.setConsoleCommunication(debugConsoleCommunication);
+
+
+ PydevDebugConsoleExecuteActionHandler consoleExecuteActionHandler = new PydevDebugConsoleExecuteActionHandler(pythonConsoleView,
+ processHandler,
+ debugConsoleCommunication);
+ pythonConsoleView.setExecutionHandler(consoleExecuteActionHandler);
+
+ debugProcess.getSession().addSessionListener(consoleExecuteActionHandler);
+ new LanguageConsoleBuilder(pythonConsoleView).processHandler(processHandler).initActions(consoleExecuteActionHandler, "py");
+
+ return debugConsoleCommunication;
+ }
+
@Nullable
private static CommandLinePatcher createRunConfigPatcher(RunProfileState state, RunProfile profile) {
CommandLinePatcher runConfigPatcher = null;
diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java b/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java
index 8b8a095..b4e2fe2 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.debugger;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
@@ -42,32 +43,40 @@
doEvaluate(expression, callback, true);
}
- private void doEvaluate(String expression, XEvaluationCallback callback, boolean doTrunc) {
- expression = expression.trim();
- if (expression.isEmpty()) {
- callback.evaluated(NONE);
- return;
- }
+ private void doEvaluate(final String expr, final XEvaluationCallback callback, final boolean doTrunc) {
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ String expression = expr.trim();
+ if (expression.isEmpty()) {
+ callback.evaluated(NONE);
+ return;
+ }
- final boolean isExpression = PyDebugSupportUtils.isExpression(myProject, expression);
- try {
- // todo: think on getting results from EXEC
- final PyDebugValue value = myDebugProcess.evaluate(expression, !isExpression, doTrunc);
- if (value.isErrorOnEval()) {
- callback.errorOccurred("{" + value.getType() + "}" + value.getValue());
+ final boolean isExpression = PyDebugSupportUtils.isExpression(myProject, expression);
+ try {
+ // todo: think on getting results from EXEC
+ final PyDebugValue value = myDebugProcess.evaluate(expression, !isExpression, doTrunc);
+ if (value.isErrorOnEval()) {
+ callback.errorOccurred("{" + value.getType() + "}" + value.getValue());
+ }
+ else {
+ callback.evaluated(value);
+ }
+ }
+ catch (PyDebuggerException e) {
+ callback.errorOccurred(e.getTracebackError());
+ }
}
- else {
- callback.evaluated(value);
- }
- }
- catch (PyDebuggerException e) {
- callback.errorOccurred(e.getTracebackError());
- }
+ });
}
@Nullable
@Override
- public TextRange getExpressionRangeAtOffset(final Project project, final Document document, final int offset, boolean sideEffectsAllowed) {
+ public TextRange getExpressionRangeAtOffset(final Project project,
+ final Document document,
+ final int offset,
+ boolean sideEffectsAllowed) {
return PyDebugSupportUtils.getExpressionRangeAtOffset(project, document, offset);
}
diff --git a/python/src/com/jetbrains/python/documentation/PyStructuredDocstringFormatter.java b/python/src/com/jetbrains/python/documentation/PyStructuredDocstringFormatter.java
index b439a54..e54f864 100644
--- a/python/src/com/jetbrains/python/documentation/PyStructuredDocstringFormatter.java
+++ b/python/src/com/jetbrains/python/documentation/PyStructuredDocstringFormatter.java
@@ -56,7 +56,7 @@
if (modules.length == 0) return Lists.newArrayList();
module = modules[0];
}
-
+ if (module == null) return Lists.newArrayList();
final PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
final List<String> result = new ArrayList<String>();
diff --git a/python/src/com/jetbrains/python/editor/PythonCopyPasteProcessor.java b/python/src/com/jetbrains/python/editor/PythonCopyPasteProcessor.java
index fee27f9..8d647cd 100644
--- a/python/src/com/jetbrains/python/editor/PythonCopyPasteProcessor.java
+++ b/python/src/com/jetbrains/python/editor/PythonCopyPasteProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,6 +50,7 @@
return null;
}
+ @NotNull
@Override
public String preprocessOnPaste(Project project,
PsiFile file,
diff --git a/python/src/com/jetbrains/python/editor/PythonDocCommentUtil.java b/python/src/com/jetbrains/python/editor/PythonDocCommentUtil.java
index 7d6baa1..03f30c1 100644
--- a/python/src/com/jetbrains/python/editor/PythonDocCommentUtil.java
+++ b/python/src/com/jetbrains/python/editor/PythonDocCommentUtil.java
@@ -83,11 +83,12 @@
boolean lookNext = false;
boolean add = true;
for (String s : subLines) {
- if (s.trim().equals(prefix + "param")) {
+ final String trimmedLine = s.trim();
+ if (trimmedLine.equals(prefix + "param") || trimmedLine.equals(prefix + "type")) {
lookNext = true;
}
- if (lookNext && s.trim().endsWith(":")) {
- String tmp = s.trim().substring(0, s.trim().length() - 1);
+ if (lookNext && trimmedLine.endsWith(":")) {
+ String tmp = trimmedLine.substring(0, trimmedLine.length() - 1);
if (paramName.equals(tmp)) {
lookNext = false;
skipNext = true;
diff --git a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
index c055606..d0a97c7 100644
--- a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
+++ b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
@@ -45,7 +45,7 @@
* @author yole
*/
public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
- private boolean needPostProcess = false;
+ private int myPostprocessShift = 0;
public static final Class[] IMPLICIT_WRAP_CLASSES = new Class[] {
PySequenceExpression.class,
@@ -129,7 +129,7 @@
final PsiElement prevElement = file.findElementAt(offset - 1);
PyStringLiteralExpression string = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PyStringLiteralExpression.class, false);
- if (string != null && PyTokenTypes.STRING_NODES.contains(prevElement.getNode().getElementType())
+ if (string != null && prevElement != null && PyTokenTypes.STRING_NODES.contains(prevElement.getNode().getElementType())
&& string.getTextOffset() < offset && !(element.getNode() instanceof PsiWhiteSpace)) {
final String stringText = element.getText();
final int prefixLength = PyStringLiteralExpressionImpl.getPrefixLength(stringText);
@@ -144,7 +144,7 @@
if (nextIsBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;
final StringBuilder replacementString = new StringBuilder();
- needPostProcess = true;
+ myPostprocessShift = prefixLength + quote.length();
if (PsiTreeUtil.getParentOfType(string, IMPLICIT_WRAP_CLASSES) != null) {
replacementString.append(quote).append(pref).append(quote);
@@ -345,9 +345,9 @@
public Result postProcessEnter(@NotNull PsiFile file,
@NotNull Editor editor,
@NotNull DataContext dataContext) {
- if (needPostProcess) {
- needPostProcess = false;
- editor.getCaretModel().moveCaretRelatively(1, 0, false, false, false);
+ if (myPostprocessShift > 0) {
+ editor.getCaretModel().moveCaretRelatively(myPostprocessShift, 0, false, false, false);
+ myPostprocessShift = 0;
}
return super.postProcessEnter(file, editor,
dataContext);
diff --git a/python/src/com/jetbrains/python/facet/FacetLibraryConfigurator.java b/python/src/com/jetbrains/python/facet/FacetLibraryConfigurator.java
index 7f01830..a2a60e4 100644
--- a/python/src/com/jetbrains/python/facet/FacetLibraryConfigurator.java
+++ b/python/src/com/jetbrains/python/facet/FacetLibraryConfigurator.java
@@ -21,11 +21,14 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.OrderEntryUtil;
+import com.intellij.openapi.roots.impl.libraries.LibraryImpl;
+import com.intellij.openapi.roots.impl.libraries.LibraryTableBase;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.python.library.PythonLibraryType;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
@@ -40,7 +43,10 @@
private FacetLibraryConfigurator() {
}
- public static void attachLibrary(final Module module, @Nullable final ModifiableRootModel existingModel, final String libraryName, final List<String> paths) {
+ public static void attachPythonLibrary(final Module module,
+ @Nullable final ModifiableRootModel existingModel,
+ final String libraryName,
+ final List<String> paths) {
final ModifiableModelsProvider modelsProvider = ModifiableModelsProvider.SERVICE.getInstance();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
@@ -51,6 +57,12 @@
// update existing
Library lib = orderEntry.getLibrary();
if (lib != null) {
+ if (lib instanceof LibraryImpl && ((LibraryImpl)lib).getKind() == null) { // replace old python libraries with python specific ones
+ model.removeOrderEntry(orderEntry);
+ ProjectLibraryTable.getInstance(model.getProject()).removeLibrary(lib);
+ createNewLibrary(model);
+ return;
+ }
fillLibrary(module.getProject(), lib, paths);
if (existingModel == null) {
modelsProvider.commitModuleModifiableModel(model);
@@ -59,8 +71,13 @@
}
}
// create new
- final LibraryTable.ModifiableModel projectLibrariesModel = modelsProvider.getLibraryTableModifiableModel(model.getProject());
- Library lib = projectLibrariesModel.createLibrary(libraryName);
+ createNewLibrary(model);
+ }
+
+ private void createNewLibrary(ModifiableRootModel model) {
+ final LibraryTableBase.ModifiableModelEx projectLibrariesModel =
+ (LibraryTableBase.ModifiableModelEx)modelsProvider.getLibraryTableModifiableModel(model.getProject());
+ Library lib = projectLibrariesModel.createLibrary(libraryName, PythonLibraryType.getInstance().getKind());
fillLibrary(module.getProject(), lib, paths);
projectLibrariesModel.commit();
model.addLibraryEntry(lib);
@@ -101,7 +118,7 @@
modifiableModel.commit();
}
- public static void detachLibrary(final Module module, final String libraryName) {
+ public static void detachPythonLibrary(final Module module, final String libraryName) {
final ModifiableModelsProvider modelsProvider = ModifiableModelsProvider.SERVICE.getInstance();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
index 2f694b6..0a6ff6e 100644
--- a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
@@ -127,11 +127,8 @@
}
private boolean isEqual(PyExpression key, PyExpression defaultValue) {
- if (key instanceof PyNumericLiteralExpression && defaultValue instanceof PyNumericLiteralExpression) {
- if (key.getText().equals(defaultValue.getText()))
- return true;
- }
- if (key instanceof PyBinaryExpression && defaultValue instanceof PyBinaryExpression) {
+ if (isBothInstanceOf(key, defaultValue, PyNumericLiteralExpression.class) ||
+ isBothInstanceOf(key, defaultValue, PyPrefixExpression.class) || isBothInstanceOf(key, defaultValue, PyBinaryExpression.class)) {
if (key.getText().equals(defaultValue.getText()))
return true;
}
@@ -155,5 +152,11 @@
}
return false;
}
+
+ private static boolean isBothInstanceOf(@NotNull final PyExpression key,
+ @NotNull final PyExpression defaultValue,
+ @NotNull final Class clazz) {
+ return clazz.isInstance(key) && clazz.isInstance(defaultValue);
+ }
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
index fddb069..c8a40a0 100644
--- a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
@@ -29,13 +29,13 @@
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
-import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeChecker;
@@ -234,9 +234,20 @@
}
}
- PyFromImportStatement fromImportStatement = PsiTreeUtil.getParentOfType(importElement, PyFromImportStatement.class);
- if (fromImportStatement != null)
+ final PyFromImportStatement fromImportStatement = PsiTreeUtil.getParentOfType(importElement, PyFromImportStatement.class);
+ if (fromImportStatement != null) {
+ for (int i = 0; i != myVersionsToProcess.size(); ++i) {
+ LanguageLevel languageLevel = myVersionsToProcess.get(i);
+ final QualifiedName qName = importElement.getImportedQName();
+ final QualifiedName sourceQName = fromImportStatement.getImportSourceQName();
+ if (qName != null && sourceQName != null && qName.matches("unicode_literals") &&
+ sourceQName.matches("__future__") && languageLevel.isOlderThan(LanguageLevel.PYTHON26)) {
+ len = appendLanguageLevel(message, len, languageLevel);
+ }
+ }
+ commonRegisterProblem(message, " not have unicode_literals in __future__ module", len, importElement, null);
return;
+ }
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
LanguageLevel languageLevel = myVersionsToProcess.get(i);
diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java
index 4062a69..68b74b6 100644
--- a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,7 +81,7 @@
final PyClass cls = ((PyClassType)type).getPyClass();
final String name = node.getName();
if (name != null) {
- final Pair<PyClass, String> key = new Pair<PyClass, String>(cls, name);
+ final Pair<PyClass, String> key = Pair.create(cls, name);
final Property property;
if (myPropertyCache.containsKey(key)) {
property = myPropertyCache.get(key);
diff --git a/python/src/com/jetbrains/python/inspections/PyRedundantParenthesesInspection.java b/python/src/com/jetbrains/python/inspections/PyRedundantParenthesesInspection.java
index c4f0712..6d777b5 100644
--- a/python/src/com/jetbrains/python/inspections/PyRedundantParenthesesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyRedundantParenthesesInspection.java
@@ -108,6 +108,9 @@
}
}
}
+ else if (expression instanceof PyParenthesizedExpression) {
+ registerProblem(expression, "Remove redundant parentheses", new RedundantParenthesesQuickFix());
+ }
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
index f3426fa..d416f1b 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
@@ -758,7 +758,7 @@
actions.add(new AddMethodQuickFix(refText, cls.getName(), true));
}
else if (!(reference instanceof PyOperatorReference)) {
- actions.add(new AddFieldQuickFix(refText, "None", type.getName()));
+ actions.add(new AddFieldQuickFix(refText, "None", type.getName(), true));
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java
index 968a723..55feead 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java
@@ -297,10 +297,17 @@
}
}
}
- final LocalQuickFix[] fixes = mayBeField
- ? new LocalQuickFix[] { new AddFieldQuickFix(name, name, containingClass.getName()) }
- : new LocalQuickFix[] { new PyRemoveParameterQuickFix() };
- registerWarning(element, PyBundle.message("INSP.unused.locals.parameter.isnot.used", name), fixes);
+ boolean canRemove = !(PsiTreeUtil.getPrevSiblingOfType(element, PyParameter.class) instanceof PySingleStarParameter) ||
+ PsiTreeUtil.getNextSiblingOfType(element, PyParameter.class) != null;
+
+ final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
+ if (mayBeField) {
+ fixes.add(new AddFieldQuickFix(name, name, containingClass.getName(), false));
+ }
+ if (canRemove) {
+ fixes.add(new PyRemoveParameterQuickFix());
+ }
+ registerWarning(element, PyBundle.message("INSP.unused.locals.parameter.isnot.used", name), fixes.toArray(new LocalQuickFix[fixes.size()]));
}
else {
if (myIgnoreTupleUnpacking && isTupleUnpacking(element)) {
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
index 27134f1..c257143 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
@@ -24,6 +24,7 @@
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -139,7 +140,7 @@
private static void addParametersFromSuper(@NotNull final PyFunction superInit, @NotNull final StringBuilder superCall,
@NotNull final StringBuilder newFunction, boolean addComma,
@NotNull final List<String> problemParams, @NotNull final List<String> functionParams,
- String starName, String doubleStarName) {
+ @Nullable String starName, @Nullable String doubleStarName) {
final PyParameterList paramList = superInit.getParameterList();
PyParameter[] parameters = paramList.getParameters();
boolean addDouble = false;
@@ -170,16 +171,20 @@
}
for(String p : problemParams)
newFunction.append(",").append(p);
- if (addStar) {
+ if (starName != null) {
newFunction.append(",").append(starName);
- if (addComma) superCall.append(",");
- superCall.append(starName);
- addComma = true;
+ if (addStar) {
+ if (addComma) superCall.append(",");
+ superCall.append(starName);
+ addComma = true;
+ }
}
- if (addDouble) {
- if (addComma) superCall.append(",");
- superCall.append(doubleStarName);
+ if (doubleStarName != null) {
newFunction.append(",").append(doubleStarName);
+ if (addDouble) {
+ if (addComma) superCall.append(",");
+ superCall.append(doubleStarName);
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java
index 9ea0507..8ecd8a5 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java
@@ -55,11 +55,13 @@
private final String myInitializer;
private final String myClassName;
private String myIdentifier;
+ private boolean replaceInitializer = false;
- public AddFieldQuickFix(@NotNull final String identifier, @NotNull final String initializer, final String className) {
+ public AddFieldQuickFix(@NotNull final String identifier, @NotNull final String initializer, final String className, boolean replace) {
myIdentifier = identifier;
myInitializer = initializer;
myClassName = className;
+ replaceInitializer = replace;
}
@NotNull
@@ -128,8 +130,12 @@
if (initStatement instanceof PyAssignmentStatement) {
final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(initStatement);
final PyExpression assignedValue = ((PyAssignmentStatement)initStatement).getAssignedValue();
- if (assignedValue != null) {
- builder.replaceElement(assignedValue, myInitializer);
+ final PyExpression leftExpression = ((PyAssignmentStatement)initStatement).getLeftHandSideExpression();
+ if (assignedValue != null && leftExpression != null) {
+ if (replaceInitializer)
+ builder.replaceElement(assignedValue, myInitializer);
+ else
+ builder.replaceElement(leftExpression.getLastChild(), myIdentifier);
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return;
final Editor editor = FileEditorManager.getInstance(file.getProject()).openTextEditor(
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/CompatibilityPrintCallQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/CompatibilityPrintCallQuickFix.java
index a294b5d..bd89366 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/CompatibilityPrintCallQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/CompatibilityPrintCallQuickFix.java
@@ -23,9 +23,7 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function;
import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.psi.LanguageLevel;
-import com.jetbrains.python.psi.PyElementGenerator;
-import com.jetbrains.python.psi.PyExpression;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
@@ -51,9 +49,9 @@
}
private static void replacePrint(PsiElement expression, PyElementGenerator elementGenerator) {
- StringBuilder stringBuilder = new StringBuilder("print(");
-
- PyExpression[] target = PsiTreeUtil.getChildrenOfType(expression, PyExpression.class);
+ final StringBuilder stringBuilder = new StringBuilder("print(");
+ final PyFile file = (PyFile)expression.getContainingFile();
+ final PyExpression[] target = PsiTreeUtil.getChildrenOfType(expression, PyExpression.class);
if (target != null) {
stringBuilder.append(StringUtil.join(target, new Function<PyExpression, String>() {
@Override
@@ -62,9 +60,12 @@
}
}, ", "));
}
-
stringBuilder.append(")");
expression.replace(elementGenerator.createFromText(LanguageLevel.forElement(expression), PyExpression.class,
stringBuilder.toString()));
+
+ final PyFromImportStatement statement = elementGenerator.createFromText(LanguageLevel.forElement(expression), PyFromImportStatement.class,
+ "from __future__ import print_function");
+ file.addBefore(statement, file.getStatements().get(0));
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java
index 84935b8..81abc77 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java
@@ -23,14 +23,20 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.usageView.UsageInfo;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.editor.PythonDocCommentUtil;
import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.refactoring.PyRefactoringUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import java.util.List;
+import java.util.Map;
+
public class PyRemoveParameterQuickFix implements LocalQuickFix {
@NotNull
@@ -49,18 +55,26 @@
assert element instanceof PyParameter;
final PyFunction pyFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class);
- final PsiElement nextSibling = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
- final PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace.class);
- element.delete();
- if (nextSibling != null && nextSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) {
- nextSibling.delete();
- return;
- }
- if (prevSibling != null && prevSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) {
- prevSibling.delete();
- }
if (pyFunction != null) {
+ final List<UsageInfo> usages = PyRefactoringUtil.findUsages(pyFunction, false);
+ for (UsageInfo usage : usages) {
+ final PsiElement usageElement = usage.getElement();
+ if (usageElement != null) {
+ final PsiElement callExpression = usageElement.getParent();
+ if (callExpression instanceof PyCallExpression) {
+ final PyArgumentList argumentList = ((PyCallExpression)callExpression).getArgumentList();
+ if (argumentList != null) {
+ final CallArgumentsMapping mapping = argumentList.analyzeCall(PyResolveContext.noImplicits());
+ for (Map.Entry<PyExpression, PyNamedParameter> parameterEntry : mapping.getPlainMappedParams().entrySet()) {
+ if (parameterEntry.getValue().equals(element)) {
+ parameterEntry.getKey().delete();
+ }
+ }
+ }
+ }
+ }
+ }
final PyStringLiteralExpression expression = pyFunction.getDocStringExpression();
final String paramName = ((PyParameter)element).getName();
if (expression != null && paramName != null) {
@@ -74,5 +88,17 @@
expression.replace(str);
}
}
+
+ final PsiElement nextSibling = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
+ final PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace.class);
+ element.delete();
+ if (nextSibling != null && nextSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) {
+ nextSibling.delete();
+ return;
+ }
+ if (prevSibling != null && prevSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) {
+ prevSibling.delete();
+ }
+
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
index 1455d7a..95daf46 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
@@ -21,6 +21,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExpression;
@@ -46,16 +47,19 @@
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement expression = descriptor.getPsiElement();
if (expression != null && expression.isWritable() && expression instanceof PyReferenceExpression) {
- PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
- if ("print".equals(expression.getText()))
- replacePrint(expression, elementGenerator);
+ final String expressionText = expression.getText();
+ if (PyNames.PRINT.equals(expressionText) || PyNames.EXEC.equals(expressionText))
+ replacePrintExec(expression);
else
- expression.replace(elementGenerator.createCallExpression(LanguageLevel.forElement(expression), expression.getText()));
+ expression.replace(PyElementGenerator.getInstance(project).createCallExpression(LanguageLevel.forElement(expression),
+ expressionText));
}
}
- private static void replacePrint(PsiElement expression, PyElementGenerator elementGenerator) {
- StringBuilder stringBuilder = new StringBuilder("print (");
+ private static void replacePrintExec(@NotNull final PsiElement expression) {
+ final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(expression.getProject());
+ final String expressionText = expression.getText();
+ final StringBuilder stringBuilder = new StringBuilder(expressionText + " (");
final PsiElement whiteSpace = expression.getContainingFile().findElementAt(expression.getTextOffset() + expression.getTextLength());
PsiElement next = null;
@@ -76,7 +80,7 @@
if (next != null) {
final String text = next.getText();
stringBuilder.append(text);
- if (text.endsWith(","))
+ if (text.endsWith(",") && PyNames.PRINT.equals(expressionText))
stringBuilder.append(" end=' '");
next.delete();
}
diff --git a/python/src/com/jetbrains/python/library/PythonLibraryType.java b/python/src/com/jetbrains/python/library/PythonLibraryType.java
new file mode 100644
index 0000000..70925e9
--- /dev/null
+++ b/python/src/com/jetbrains/python/library/PythonLibraryType.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.library;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.libraries.DummyLibraryProperties;
+import com.intellij.openapi.roots.libraries.LibraryType;
+import com.intellij.openapi.roots.libraries.NewLibraryConfiguration;
+import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
+import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent;
+import com.intellij.openapi.roots.libraries.ui.LibraryPropertiesEditor;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * python library type should be used if library paths to be included in Python Path
+ */
+public class PythonLibraryType extends LibraryType<DummyLibraryProperties> {
+ private static final PersistentLibraryKind<DummyLibraryProperties> LIBRARY_KIND = new PersistentLibraryKind<DummyLibraryProperties>("python") {
+ @NotNull
+ @Override
+ public DummyLibraryProperties createDefaultProperties() {
+ return DummyLibraryProperties.INSTANCE;
+ }
+ };
+
+ protected PythonLibraryType() {
+ super(LIBRARY_KIND);
+ }
+
+ public static PythonLibraryType getInstance() {
+ return EP_NAME.findExtension(PythonLibraryType.class);
+ }
+
+ @Override
+ public String getCreateActionName() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public NewLibraryConfiguration createNewLibrary(@NotNull JComponent parentComponent,
+ @Nullable VirtualFile contextDirectory,
+ @NotNull Project project) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public LibraryPropertiesEditor createPropertiesEditor(@NotNull LibraryEditorComponent<DummyLibraryProperties> editorComponent) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return null;
+ }
+
+}
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralExtensionPoint.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralExtensionPoint.java
index 3adf05fc..3ac6156 100644
--- a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralExtensionPoint.java
+++ b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralExtensionPoint.java
@@ -1,9 +1,8 @@
package com.jetbrains.python.magicLiteral;
import com.intellij.openapi.extensions.ExtensionPointName;
-import com.jetbrains.python.psi.PyStringLiteralExpression;
+import com.jetbrains.python.psi.StringLiteralExpression;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* Any magic literal extension point should imlement this interface and be installed as extesnion point
@@ -21,7 +20,7 @@
* @param element element to check
* @return true if magic.
*/
- boolean isMagicLiteral(@NotNull PyStringLiteralExpression element);
+ boolean isMagicLiteral(@NotNull StringLiteralExpression element);
/**
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java
new file mode 100644
index 0000000..0a801b1
--- /dev/null
+++ b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralRenameHandler.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.magicLiteral;
+
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.refactoring.rename.RenameDialog;
+import com.intellij.refactoring.rename.RenameHandler;
+import com.jetbrains.python.psi.PyStringLiteralExpression;
+import com.jetbrains.python.psi.StringLiteralExpression;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author traff
+ */
+public class PyMagicLiteralRenameHandler implements RenameHandler {
+ @Override
+ public boolean isAvailableOnDataContext(DataContext dataContext) {
+ final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ if (editor == null) {
+ return false;
+ }
+
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext);
+ if (file == null) {
+ return false;
+ }
+
+ final PsiElement element = getElement(file, editor);
+
+ if (element == null || !PyMagicLiteralTools.isMagicLiteral(element)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Nullable
+ private static PsiElement getElement(PsiFile file, Editor editor) {
+ PsiElement element = file.findElementAt(editor.getCaretModel().getCurrentCaret().getOffset());
+ if (element instanceof PyStringLiteralExpression) {
+ return element;
+ }
+ return PsiTreeUtil.getParentOfType(element, StringLiteralExpression.class);
+ }
+
+ @Override
+ public boolean isRenaming(DataContext dataContext) {
+ return isAvailableOnDataContext(dataContext);
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
+ PsiElement element = getElement(file, editor);
+ if (element == null) {
+ return;
+ }
+ RenameDialog.showRenameDialog(dataContext, new RenameDialog(project, element, null, editor));
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralTools.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralTools.java
index 58118a9..d119ec0 100644
--- a/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralTools.java
+++ b/python/src/com/jetbrains/python/magicLiteral/PyMagicLiteralTools.java
@@ -2,7 +2,7 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiElement;
-import com.jetbrains.python.psi.PyStringLiteralExpression;
+import com.jetbrains.python.psi.StringLiteralExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -23,7 +23,7 @@
* @return true if magic
*/
public static boolean isMagicLiteral(@NotNull final PsiElement element) {
- return (element instanceof PyStringLiteralExpression) && (getPoint((PyStringLiteralExpression)element) != null);
+ return (element instanceof StringLiteralExpression) && (getPoint((StringLiteralExpression)element) != null);
}
/**
@@ -33,7 +33,7 @@
* @return extension point (if any) or null if literal is unknown to all installed magic literal extesnion points
*/
@Nullable
- public static PyMagicLiteralExtensionPoint getPoint(@NotNull final PyStringLiteralExpression element) {
+ public static PyMagicLiteralExtensionPoint getPoint(@NotNull final StringLiteralExpression element) {
final PyMagicLiteralExtensionPoint[] magicLiteralExtPoints =
ApplicationManager.getApplication().getExtensions(PyMagicLiteralExtensionPoint.EP_NAME);
diff --git a/python/src/com/jetbrains/python/magicLiteral/PyMagicTargetElementExtensionPoint.java b/python/src/com/jetbrains/python/magicLiteral/PyMagicTargetElementExtensionPoint.java
deleted file mode 100644
index 40134e3..0000000
--- a/python/src/com/jetbrains/python/magicLiteral/PyMagicTargetElementExtensionPoint.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.jetbrains.python.magicLiteral;
-
-import com.intellij.codeInsight.TargetElementExtensionPoint;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.jetbrains.python.psi.PyStringLiteralExpression;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Makes magic literals work as target elements (to support renaming)
- * <strong>Install it</strong> as {@link com.intellij.codeInsight.TargetElementExtensionPoint}
- *
- * @author Ilya.Kazakevich
- */
-class PyMagicTargetElementExtensionPoint implements TargetElementExtensionPoint {
- @Nullable
- @Override
- public PsiElement getNearestTargetElement(@NotNull final PsiElement element) {
- final PyStringLiteralExpression literalExpression = PsiTreeUtil.getParentOfType(element, PyStringLiteralExpression.class);
- if ((literalExpression != null) && (PyMagicLiteralTools.isMagicLiteral(literalExpression))) {
- return literalExpression;
- }
- return null;
- }
-}
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
index 3e31733a..0b65e70 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
@@ -717,7 +717,7 @@
else {
credentials = "";
}
- return credentials + String.format("%s:%d", settings.PROXY_HOST, settings.PROXY_PORT);
+ return "http://" + credentials + String.format("%s:%d", settings.PROXY_HOST, settings.PROXY_PORT);
}
return null;
}
diff --git a/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java
new file mode 100644
index 0000000..2fd5694
--- /dev/null
+++ b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.projectView;
+
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiManager;
+import com.intellij.util.PlatformIcons;
+import com.jetbrains.python.sdk.PySdkUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author traff
+ */
+public class PyRemoteLibrariesNode extends PsiDirectoryNode {
+ private PyRemoteLibrariesNode(Project project, PsiDirectory value, ViewSettings viewSettings) {
+ super(project, value, viewSettings);
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ data.setPresentableText("Remote Libraries");
+ data.setIcon(PlatformIcons.LIBRARY_ICON);
+ }
+
+ @Nullable
+ public static PyRemoteLibrariesNode create(@NotNull Project project, @NotNull Sdk sdk, ViewSettings settings) {
+ final VirtualFile remoteLibraries = PySdkUtil.findRemoteLibrariesDir(sdk);
+ if (remoteLibraries != null) {
+ final PsiDirectory remoteLibrariesDirectory = PsiManager.getInstance(project).findDirectory(remoteLibraries);
+ return new PyRemoteLibrariesNode(project, remoteLibrariesDirectory, settings);
+ }
+ return null;
+ }
+}
diff --git a/python/src/com/jetbrains/python/projectView/PySkeletonsNode.java b/python/src/com/jetbrains/python/projectView/PySkeletonsNode.java
index 4bdab76..01e82ed 100644
--- a/python/src/com/jetbrains/python/projectView/PySkeletonsNode.java
+++ b/python/src/com/jetbrains/python/projectView/PySkeletonsNode.java
@@ -24,7 +24,7 @@
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.util.PlatformIcons;
-import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.sdk.PySdkUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +44,7 @@
@Nullable
public static PySkeletonsNode create(@NotNull Project project, @NotNull Sdk sdk, ViewSettings settings) {
- final VirtualFile skeletonsVirtualFile = PythonSdkType.findSkeletonsDir(sdk);
+ final VirtualFile skeletonsVirtualFile = PySdkUtil.findSkeletonsDir(sdk);
if (skeletonsVirtualFile != null) {
final PsiDirectory skeletonsDirectory = PsiManager.getInstance(project).findDirectory(skeletonsVirtualFile);
return new PySkeletonsNode(project, skeletonsDirectory, settings);
diff --git a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
index 7b711a3..dedc82e 100644
--- a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
+++ b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
@@ -36,6 +36,7 @@
import com.jetbrains.python.psi.PyDocStringOwner;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
+import com.jetbrains.python.remote.PyRemoteSdkCredentials;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -63,6 +64,10 @@
if (userSkeletonsNode != null) {
newChildren.add(userSkeletonsNode);
}
+ final PyRemoteLibrariesNode remoteLibrariesNode = PyRemoteLibrariesNode.create(project, sdk, settings);
+ if (remoteLibrariesNode != null) {
+ newChildren.add(remoteLibrariesNode);
+ }
return newChildren;
}
if (settings.isShowMembers()) {
diff --git a/python/src/com/jetbrains/python/psi/PsiQuery.java b/python/src/com/jetbrains/python/psi/PsiQuery.java
new file mode 100644
index 0000000..f0893e9
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/PsiQuery.java
@@ -0,0 +1,331 @@
+package com.jetbrains.python.psi;
+
+import com.intellij.openapi.util.Condition;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.nameResolver.FQNamesProvider;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * JQuery-like tool that makes PSI navigation easier.
+ * You just "drive" your query filtering results, and no need to check result for null.
+ *
+ * @author Ilya.Kazakevich
+ */
+public class PsiQuery {
+ private static final PsiQuery EMPTY = new PsiQuery();
+ @NotNull
+ private final PsiElement[] myPsiElements;
+
+ /**
+ * @param psiElement one or more elements to start
+ */
+ public PsiQuery(@NotNull final PsiElement... psiElement) {
+ myPsiElements = psiElement.clone();
+ }
+
+
+ /**
+ * @param psiElements one or more elements to start
+ */
+ public PsiQuery(@NotNull final List<? extends PsiElement> psiElements) {
+ this(psiElements.toArray(new PsiElement[psiElements.size()]));
+ }
+
+ /**
+ * Filter children by name
+ */
+ @NotNull
+ public PsiQuery childrenNamed(@NotNull final String name) {
+ return childrenNamed(PsiNamedElement.class, name);
+ }
+
+ /**
+ * Filter children by name and class
+ */
+ @NotNull
+ public PsiQuery childrenNamed(@NotNull final Class<? extends PsiNamedElement> clazz, @NotNull final String name) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ for (final PsiNamedElement child : PsiTreeUtil.findChildrenOfType(element, clazz)) {
+ if (name.equals(child.getName())) {
+ result.add(child);
+ }
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * TODO: Support types?
+ * Filter children by function call
+ * @return {@link com.jetbrains.python.psi.PsiQuery} backed by {@link com.jetbrains.python.psi.PyCallExpression}
+ */
+ @NotNull
+ public PsiQuery childrenCall(@NotNull final FQNamesProvider name) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ for (final PyCallExpression call : PsiTreeUtil.findChildrenOfType(element, PyCallExpression.class)) {
+ if (call.isCallee(name)) {
+ result.add(call);
+ }
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+ /**
+ * Filter children by class
+ */
+ @NotNull
+ public PsiQuery children(@NotNull final Class<? extends PsiElement> clazz) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ result.addAll(PsiTreeUtil.findChildrenOfType(element, clazz));
+ }
+
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Filter parents by name
+ */
+ @NotNull
+ public PsiQuery parents(@NotNull final String name) {
+ throw new RuntimeException("Not implemented");
+ }
+
+
+ /**
+ * Filter parents by name and class
+ */
+ @NotNull
+ public PsiQuery parents(@NotNull final Class<? extends PsiElement> clazz) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ final PsiElement parent = PsiTreeUtil.getParentOfType(element, clazz);
+ if (parent != null) {
+ result.add(parent);
+ }
+ }
+ return new PsiQuery(result);
+ }
+
+
+ /**
+ * Filter parents by condition
+ */
+ @NotNull
+ public PsiQuery parents(@NotNull final Condition<Class<? extends PsiElement>> condition) {
+ throw new RuntimeException("Not impl");
+ }
+
+
+ /**
+ * Filter parents by class and name
+ */
+ @NotNull
+ public PsiQuery parents(@NotNull final Class<? extends PsiElement> clazz, @NotNull final String name) {
+ throw new RuntimeException("Not impl");
+ }
+
+
+ /**
+ * Filter parents by function call
+ */
+ @NotNull
+ public PsiQuery parents(@NotNull final FQNamesProvider name) {
+ throw new RuntimeException("Not impl");
+ }
+
+
+ /**
+ * Filter siblings by name
+ */
+ @NotNull
+ public PsiQuery siblings(@NotNull final String name) {
+ return siblings(PsiNamedElement.class, name);
+ }
+
+
+ /**
+ * Filter siblings by class
+ */
+ @NotNull
+ public PsiQuery siblings(@NotNull final Class<? extends PsiElement> clazz) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ final PsiElement parent = element.getParent();
+ for (final PsiElement sibling : PsiTreeUtil.findChildrenOfType(parent, clazz)) {
+ if ((!sibling.equals(element))) {
+ result.add(sibling);
+ }
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Filter siblings by name and class
+ */
+ @NotNull
+ public PsiQuery siblings(@NotNull final Class<? extends PsiNamedElement> clazz, @NotNull final String name) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ final PsiElement parent = element.getParent();
+ for (final PsiNamedElement namedSibling : PsiTreeUtil.findChildrenOfType(parent, clazz)) {
+ if ((!namedSibling.equals(element)) && (name.equals(namedSibling.getName()))) {
+ result.add(namedSibling);
+ }
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Filter siblings by function call name
+ */
+ @NotNull
+ public PsiQuery siblings(@NotNull final FQNamesProvider name) {
+ final List<PsiElement> result = new ArrayList<PsiElement>();
+ for (final PsiElement element : myPsiElements) {
+ final PsiElement parent = element.getParent();
+ for (final PyCallExpression callSibling : PsiTreeUtil.findChildrenOfType(parent, PyCallExpression.class)) {
+ if ((!callSibling.equals(element)) && (callSibling.isCallee(name))) {
+ result.add(callSibling);
+ }
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Get first element from result only
+ */
+ @NotNull
+ public PsiQuery first() {
+ return (myPsiElements.length > 0) ? new PsiQuery(myPsiElements[0]) : EMPTY;
+ }
+
+
+ /**
+ * Get last element from result only
+ */
+ @NotNull
+ public PsiQuery last() {
+ return (myPsiElements.length > 0) ? new PsiQuery(myPsiElements[myPsiElements.length - 1]) : EMPTY;
+ }
+
+
+ /**
+ * Get first element from result only if certain class
+ */
+ @Nullable
+ public <T extends PsiElement> T getFirstElement(@NotNull final Class<T> expectedClass) {
+ final List<T> elements = getChildrenElements(expectedClass);
+ if (!elements.isEmpty()) {
+ return elements.get(0);
+ }
+ return null;
+ }
+
+
+ /**
+ * Get last element from result only if certain class
+ */
+ @Nullable
+ public <T extends PsiElement> T getLastElement(@NotNull final Class<T> expectedClass) {
+ final List<T> elements = getChildrenElements(expectedClass);
+ if (!elements.isEmpty()) {
+ return elements.get(elements.size() - 1);
+ }
+ return null;
+ }
+
+
+ /**
+ * Get children elements filtered by class
+ */
+ @NotNull
+ public <T extends PsiElement> List<T> getChildrenElements(@NotNull final Class<T> expectedClass) {
+ final List<T> result = new ArrayList<T>();
+ for (final PsiElement element : myPsiElements) {
+ final T typedElement = PyUtil.as(element, expectedClass);
+ if (typedElement != null) {
+ result.add(typedElement);
+ }
+ else {
+ final T[] children = PsiTreeUtil.getChildrenOfType(element, expectedClass);
+ if (children != null) {
+ Collections.addAll(result, children);
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Filter by function call
+ */
+ @NotNull
+ public PsiQuery filter(@NotNull final FQNamesProvider name) {
+ final Set<PsiElement> result = new HashSet<PsiElement>(Arrays.asList(myPsiElements));
+ for (final PsiElement element : myPsiElements) {
+ final PyCallExpression callExpression = PyUtil.as(element, PyCallExpression.class);
+ if ((callExpression == null) || (!callExpression.isCallee(name))) {
+ result.remove(element);
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Filter by element name
+ */
+ @NotNull
+ public PsiQuery filter(@NotNull final String name) {
+ return filter(PsiNamedElement.class, name);
+ }
+
+
+ /**
+ * Filter elements by class
+ */
+ @NotNull
+ public PsiQuery filter(@NotNull final Class<? extends PsiElement> clazz) {
+ final Set<PsiElement> result = new HashSet<PsiElement>(Arrays.asList(myPsiElements));
+ for (final PsiElement element : myPsiElements) {
+ if (PyUtil.as(element, clazz) == null) {
+ result.remove(element);
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+
+
+ /**
+ * Filter elements by class and name
+ */
+ @NotNull
+ public PsiQuery filter(@NotNull final Class<? extends PsiNamedElement> clazz, @NotNull final String name) {
+ final Set<PsiElement> result = new HashSet<PsiElement>(Arrays.asList(myPsiElements));
+ for (final PsiElement element : myPsiElements) {
+ final PsiNamedElement namedElement = PyUtil.as(element, clazz);
+ if ((namedElement == null) || (!name.equals(namedElement.getName()))) {
+ result.remove(element);
+ }
+ }
+ return new PsiQuery(result.toArray(new PsiElement[result.size()]));
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java
index 49a024bc..1700a49 100644
--- a/python/src/com/jetbrains/python/psi/PyUtil.java
+++ b/python/src/com/jetbrains/python/psi/PyUtil.java
@@ -81,7 +81,6 @@
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
-import java.lang.reflect.Array;
import java.util.*;
import java.util.List;
@@ -814,13 +813,13 @@
* It saves coder from "instanceof / cast" chains.
*
* @param expression expression to check
- * @param clazz class to cast
- * @param <T> class to cast
+ * @param clazz class to cast
+ * @param <T> class to cast
* @return expression casted to appropriate type (if could be casted). Null otherwise.
*/
@Nullable
@SuppressWarnings("unchecked")
- public static <T>T as(@Nullable final Object expression, @NotNull final Class<T> clazz) {
+ public static <T> T as(@Nullable final Object expression, @NotNull final Class<T> clazz) {
if (expression == null) {
return null;
}
@@ -828,7 +827,50 @@
return (T)expression;
}
return null;
+ }
+ // TODO: Move to PsiElement?
+
+ /**
+ * Searches for references injected to element with certain type
+ *
+ * @param element element to search injected references for
+ * @param expectedClass expected type of element reference resolved to
+ * @param <T> expected type of element reference resolved to
+ * @return resolved element if found or null if not found
+ */
+ @Nullable
+ public static <T extends PsiElement> T findReference(@NotNull final PsiElement element, @NotNull final Class<T> expectedClass) {
+ for (final PsiReference reference : element.getReferences()) {
+ final T result = as(reference.resolve(), expectedClass);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Converts collection to list of certain type
+ * @param expression expression of collection type
+ * @param elementClass expected element type
+ * @param <T> expected element type
+ * @return list of elements of expected element type
+ */
+ @NotNull
+ public static <T> List<T> asList(@Nullable final Collection<?> expression, @NotNull final Class<T> elementClass) {
+ if ((expression == null) || expression.isEmpty()) {
+ return Collections.emptyList();
+ }
+ final List<T> result = new ArrayList<T>();
+ for (final Object element : expression) {
+ final T toAdd = as(element, elementClass);
+ if (toAdd != null) {
+ result.add(toAdd);
+ }
+ }
+ return result;
}
public static class KnownDecoratorProviderHolder {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyAnyExpressionEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyAnyExpressionEvaluator.java
new file mode 100644
index 0000000..b006ac1
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/PyAnyExpressionEvaluator.java
@@ -0,0 +1,105 @@
+package com.jetbrains.python.psi.impl;
+
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Evaluator tht supports expression of any type (it evaluates any expression, concatenating several expressions to list etc)
+ */
+public class PyAnyExpressionEvaluator extends PyEvaluator {
+ private final boolean myEvalSequence;
+
+ /**
+ * @param evalSequence evaluate sequencies ((a,b) + (c,d) == (a,b,c,d)) or store them as single ((a,b) + (c,d) = [(a,b), (c,d)])
+ */
+ public PyAnyExpressionEvaluator(final boolean evalSequence) {
+ myEvalSequence = evalSequence;
+ }
+
+ @NotNull
+ @Override
+ public Object evaluate(final PyExpression expr) {
+ final Object evaluate = super.evaluate(expr);
+ return ((evaluate != null) ? evaluate : expr);
+ }
+
+ @Override
+ public Object concatenate(final Object lhs, final Object rhs) {
+ final Object evaluate = super.concatenate(lhs, rhs);
+ return ((evaluate != null) ? evaluate : Arrays.asList(lhs, rhs));
+ }
+
+ @Override
+ protected Object evaluateReferenceExpression(final PyReferenceExpression expr) {
+ final Object evaluate = super.evaluateReferenceExpression(expr);
+ return ((evaluate != null) ? evaluate : expr);
+ }
+
+ @Override
+ protected Object evaluateCall(final PyCallExpression call) {
+ final Object evaluate = super.evaluateCall(call);
+ return ((evaluate != null) ? evaluate : call);
+ }
+
+ @Override
+ protected Object evaluateSequenceExpression(final PySequenceExpression expr) {
+ return myEvalSequence ? super.evaluateSequenceExpression(expr) : expr;
+ }
+
+ /**
+ * Evaluates expression to single element
+ * @param expression exp to eval
+ * @param aClass expected class
+ * @param <T> expected class
+ * @return instance of aClass, or null if failed to eval
+ */
+ @Nullable
+ public static <T> T evaluateOne(@NotNull final PyExpression expression, @NotNull final Class<T> aClass) {
+ final PyAnyExpressionEvaluator evaluator = new PyAnyExpressionEvaluator(false);
+ final Object evaluate = evaluator.evaluate(expression);
+ final T resultSingle = PyUtil.as(evaluate, aClass);
+ if (resultSingle != null) {
+ return resultSingle;
+ }
+ final List<?> resultMultiple = PyUtil.as(evaluate, List.class);
+ if ((resultMultiple != null) && !resultMultiple.isEmpty()) {
+ return PyUtil.as(resultMultiple.get(0), aClass);
+ }
+ return null;
+ }
+
+
+ /**
+ * Evaluates expression to string
+ * @param expression exp to eval
+ * @return string, or null if failed to eval
+ */
+ @Nullable
+ public static String evaluateString(@NotNull final PyExpression expression) {
+ return PyUtil.as(new PyAnyExpressionEvaluator(false).evaluate(expression), String.class);
+ }
+
+ /**
+ * Evaluates expression as list of values
+ * @param expression exp to eval
+ * @param aClass expected element class
+ * @param <T> expected element class
+ * @return a list of elements of expected type
+ */
+ @NotNull
+ public static <T>List<T> evaluateIterable(@NotNull final PyExpression expression, @NotNull final Class<T> aClass) {
+ final PyAnyExpressionEvaluator evaluator = new PyAnyExpressionEvaluator(true);
+ final Object evaluate = evaluator.evaluate(expression);
+ final T resultSingle = PyUtil.as(evaluate, aClass);
+ if (resultSingle != null) {
+ return Collections.singletonList(resultSingle);
+ }
+ return PyUtil.asList(PyUtil.as(evaluate, List.class), aClass);
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java
index d0c83cc..a92515d 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java
@@ -24,10 +24,10 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.NotNullPredicate;
+import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
-import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import org.jetbrains.annotations.NotNull;
@@ -344,8 +344,15 @@
}
final PyExpression[] arguments = getArguments();
- if (arguments.length > parameter.getPosition()) {
- return arguments[parameter.getPosition()];
+ final int position = parameter.getPosition();
+ if ((position != FunctionParameter.POSITION_NOT_SUPPORTED) && (arguments.length > position)) {
+ final PyExpression result = arguments[position];
+ if (result instanceof PyKeywordArgument) {
+ ((PyKeywordArgument)result).getValueExpression();
+ }
+ else {
+ return result;
+ }
}
return null;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
index 9f76798..c991266 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -180,7 +180,7 @@
else if (rhs != null) rhs_one = rhs;
//
if (lhs_one != null) { // single LHS, single RHS (direct mapping) or multiple RHS (packing)
- map.add(new Pair<PyExpression, PyExpression>(lhs_one, rhs));
+ map.add(Pair.create(lhs_one, rhs));
}
else if (lhs_tuple != null && rhs_one != null) { // multiple LHS, single RHS: unpacking
// PY-2648, PY-2649
@@ -190,7 +190,7 @@
for (PyExpression tuple_elt : lhs_tuple.getElements()) {
try {
final PyExpression expression = elementGenerator.createExpressionFromText(languageLevel, rhs_one.getText() + "[" + counter + "]");
- map.add(new Pair<PyExpression, PyExpression>(tuple_elt, expression));
+ map.add(Pair.create(tuple_elt, expression));
}
catch (IncorrectOperationException e) {
// not parsed, no problem
diff --git a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
index c561eb6..f23ed3a 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
@@ -25,6 +25,7 @@
import java.util.*;
/**
+ *
* @author yole
*/
public class PyBlockEvaluator {
@@ -97,7 +98,7 @@
Object currentValue = myNamespace.get(name);
if (currentValue != null) {
Object rhs = prepareEvaluator().evaluate(node.getValue());
- myNamespace.put(name, PyEvaluator.concatenate(currentValue, rhs));
+ myNamespace.put(name, prepareEvaluator().concatenate(currentValue, rhs));
}
if (myDeclarationsToTrack.contains(name)) {
List<PyExpression> declarations = myDeclarations.get(name);
@@ -187,7 +188,7 @@
Object value = myNamespace.get(nameBeingExtended);
if (value instanceof List) {
Object argValue = prepareEvaluator().evaluate(arg);
- myNamespace.put(nameBeingExtended, PyEvaluator.concatenate(value, argValue));
+ myNamespace.put(nameBeingExtended, prepareEvaluator().concatenate(value, argValue));
}
if (myDeclarationsToTrack.contains(nameBeingExtended)) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
index a626310..b9fe8c3 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.nameResolver.NameResolverTools;
@@ -86,7 +87,7 @@
PsiElement original = ((PyReferenceExpression)possible_original_ref).getReference().resolve();
if (original instanceof PyFunction) {
// pinned down the original; replace our resolved callee with it and add flags.
- return new Pair<String, PyFunction>(refname, (PyFunction)original);
+ return Pair.create(refname, (PyFunction)original);
}
}
}
@@ -361,6 +362,27 @@
return false;
}
+
+ /**
+ * Returns argument if it exists and has appropriate type
+ * @param parameter argument
+ * @param argClass expected class
+ * @param expression call expression
+ * @param <T> expected class
+ * @return argument expression or null if has wrong type of does not exist
+ */
+ @Nullable
+ public static <T extends PsiElement> T getArgument(
+ @NotNull final FunctionParameter parameter,
+ @NotNull final Class<T> argClass,
+ @NotNull final PyCallExpression expression) {
+ final PyArgumentList list = expression.getArgumentList();
+ if (list == null) {
+ return null;
+ }
+ return PyUtil.as(list.getValueExpressionForParam(parameter), argClass);
+ }
+
@Nullable
public static PyExpression getKeywordArgument(PyCallExpression expr, String keyword) {
for (PyExpression arg : expr.getArguments()) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java
index 63e8a71..70d48aa 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java
@@ -18,6 +18,7 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -72,6 +73,12 @@
return getArgument(index, argClass);
}
+ @Nullable
+ @Override
+ public <T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull final Class<T> argClass) {
+ return PyCallExpressionHelper.getArgument(parameter, argClass, this);
+ }
+
@Override
public PyExpression getKeywordArgument(String keyword) {
return PyCallExpressionHelper.getKeywordArgument(this, keyword);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
index 9be3850..cda266e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
@@ -21,6 +21,7 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
+import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
@@ -128,6 +129,12 @@
return getArgument(index, argClass);
}
+ @Nullable
+ @Override
+ public <T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull final Class<T> argClass) {
+ return PyCallExpressionHelper.getArgument(parameter, argClass, this);
+ }
+
@Override
public PyExpression getKeywordArgument(String keyword) {
return PyCallExpressionHelper.getKeywordArgument(this, keyword);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
index 1c3daa5..d4300be 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
@@ -46,28 +46,10 @@
}
myVisited.add(expr);
if (expr instanceof PyParenthesizedExpression) {
- return evaluate(((PyParenthesizedExpression) expr).getContainedExpression());
+ return evaluate(((PyParenthesizedExpression)expr).getContainedExpression());
}
if (expr instanceof PySequenceExpression) {
- PyExpression[] elements = ((PySequenceExpression)expr).getElements();
- if (expr instanceof PyDictLiteralExpression) {
- Map<Object, Object> result = new HashMap<Object, Object>();
- for (PyKeyValueExpression keyValueExpression : ((PyDictLiteralExpression)expr).getElements()) {
- Object dictKey = evaluate(keyValueExpression.getKey());
- if (dictKey != null) {
- PyExpression value = keyValueExpression.getValue();
- result.put(dictKey, myEvaluateCollectionItems ? evaluate(value) : value);
- }
- }
- return result;
- }
- else {
- List<Object> result = new ArrayList<Object>();
- for (PyExpression element : elements) {
- result.add(myEvaluateCollectionItems ? evaluate(element) : element);
- }
- return result;
- }
+ return evaluateSequenceExpression((PySequenceExpression)expr);
}
if (expr instanceof PyCallExpression) {
return evaluateCall((PyCallExpression)expr);
@@ -92,14 +74,41 @@
return null;
}
- public static Object concatenate(Object lhs, Object rhs) {
+ /**
+ * Evaluates some sequence (tuple, list)
+ * @param expr seq expression
+ * @return evaluated seq
+ */
+ protected Object evaluateSequenceExpression(PySequenceExpression expr) {
+ PyExpression[] elements = expr.getElements();
+ if (expr instanceof PyDictLiteralExpression) {
+ Map<Object, Object> result = new HashMap<Object, Object>();
+ for (PyKeyValueExpression keyValueExpression : ((PyDictLiteralExpression)expr).getElements()) {
+ Object dictKey = evaluate(keyValueExpression.getKey());
+ if (dictKey != null) {
+ PyExpression value = keyValueExpression.getValue();
+ result.put(dictKey, myEvaluateCollectionItems ? evaluate(value) : value);
+ }
+ }
+ return result;
+ }
+ else {
+ List<Object> result = new ArrayList<Object>();
+ for (PyExpression element : elements) {
+ result.add(myEvaluateCollectionItems ? evaluate(element) : element);
+ }
+ return result;
+ }
+ }
+
+ public Object concatenate(Object lhs, Object rhs) {
if (lhs instanceof String && rhs instanceof String) {
- return (String) lhs + (String) rhs;
+ return (String)lhs + (String)rhs;
}
if (lhs instanceof List && rhs instanceof List) {
List<Object> result = new ArrayList<Object>();
- result.addAll((List) lhs);
- result.addAll((List) rhs);
+ result.addAll((List)lhs);
+ result.addAll((List)rhs);
return result;
}
return null;
@@ -132,7 +141,7 @@
Object arg1 = evaluate(args[0]);
Object arg2 = evaluate(args[1]);
if (arg1 instanceof String && arg2 instanceof String) {
- return ((String) result).replace((String) arg1, (String) arg2);
+ return ((String)result).replace((String)arg1, (String)arg2);
}
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
index 794a44b..c723aed 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
@@ -87,7 +87,7 @@
final List<PyExceptPart> exceptParts = new ArrayList<PyExceptPart>();
for (PsiElement child : children) {
if (child instanceof PyExceptPart) {
- exceptParts.add((PyExceptPart) child);
+ exceptParts.add((PyExceptPart)child);
}
else {
addDeclaration(child, myLocalDeclarations, myLocalAmbiguousDeclarations, myNameDefiners);
@@ -103,7 +103,7 @@
}
}
- private void addDeclaration(PsiElement child,
+ private void addDeclaration(PsiElement child,
Map<String, PsiElement> localDeclarations,
MultiMap<String, PsiElement> ambiguousDeclarations,
List<PsiElement> nameDefiners) {
@@ -173,7 +173,7 @@
final MultiMap<String, PsiElement> ambiguousDeclarations) {
if (ambiguousDeclarations.containsKey(name)) {
final List<PsiElement> localAmbiguous = new ArrayList<PsiElement>(myLocalAmbiguousDeclarations.get(name));
- for (int i = localAmbiguous.size()-1; i >= 0; i--) {
+ for (int i = localAmbiguous.size() - 1; i >= 0; i--) {
PsiElement ambiguous = localAmbiguous.get(i);
final PsiElement result = resolveDeclaration(name, ambiguous, true);
if (result != null) {
@@ -199,7 +199,7 @@
return findNameInImportElement(name, importElement, resolveImportElement);
}
else if (result instanceof PyFromImportStatement) {
- return ((PyFromImportStatement) result).resolveImportSource();
+ return ((PyFromImportStatement)result).resolveImportSource();
}
return result;
}
@@ -289,7 +289,7 @@
@Override
public LanguageLevel getLanguageLevel() {
if (myOriginalFile != null) {
- return ((PyFileImpl) myOriginalFile).getLanguageLevel();
+ return ((PyFileImpl)myOriginalFile).getLanguageLevel();
}
VirtualFile virtualFile = getVirtualFile();
@@ -323,8 +323,9 @@
for (Language lang : getViewProvider().getLanguages()) {
final List<PythonVisitorFilter> filters = PythonVisitorFilter.INSTANCE.allForLanguage(lang);
for (PythonVisitorFilter filter : filters) {
- if (!filter.isSupported(visitorClass, this))
+ if (!filter.isSupported(visitorClass, this)) {
return false;
+ }
}
}
return true;
@@ -344,7 +345,7 @@
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
if (!processor.execute(element, state)) return false;
if (remainingDunderAll != null && element instanceof PyElement) {
- remainingDunderAll.remove(((PyElement) element).getName());
+ remainingDunderAll.remove(((PyElement)element).getName());
}
return true;
}
@@ -367,31 +368,31 @@
}
if (pyFiles.contains(this)) return true;
pyFiles.add(this);
- for(PyClass c: getTopLevelClasses()) {
+ for (PyClass c : getTopLevelClasses()) {
if (c == lastParent) continue;
if (!wrapper.execute(c, resolveState)) return false;
}
- for(PyFunction f: getTopLevelFunctions()) {
+ for (PyFunction f : getTopLevelFunctions()) {
if (f == lastParent) continue;
if (!wrapper.execute(f, resolveState)) return false;
}
- for(PyTargetExpression e: getTopLevelAttributes()) {
+ for (PyTargetExpression e : getTopLevelAttributes()) {
if (e == lastParent) continue;
if (!wrapper.execute(e, resolveState)) return false;
}
- for(PyImportElement e: getImportTargets()) {
+ for (PyImportElement e : getImportTargets()) {
if (e == lastParent) continue;
if (!wrapper.execute(e, resolveState)) return false;
}
- for(PyFromImportStatement e: getFromImports()) {
+ for (PyFromImportStatement e : getFromImports()) {
if (e == lastParent) continue;
if (!e.processDeclarations(wrapper, resolveState, null, this)) return false;
}
if (remainingDunderAll != null) {
- for (String s: remainingDunderAll) {
+ for (String s : remainingDunderAll) {
if (!PyNames.isIdentifier(s)) {
continue;
}
@@ -503,8 +504,9 @@
final QualifiedName qName = importElement.getImportedQName();
// http://stackoverflow.com/questions/6048786/from-module-import-in-init-py-makes-module-name-visible
if (qName != null && qName.getComponentCount() > 1 && name.equals(qName.getLastComponent()) && PyNames.INIT_DOT_PY.equals(getName())) {
- final List<? extends RatedResolveResult> elements = ResolveImportUtil.resolveNameInImportStatement(importElement, qName.removeLastComponent());
- for (RatedResolveResult element: elements) {
+ final List<? extends RatedResolveResult> elements =
+ ResolveImportUtil.resolveNameInImportStatement(importElement, qName.removeLastComponent());
+ for (RatedResolveResult element : elements) {
if (PyUtil.turnDirIntoInit(element.getElement()) == this) {
return importElement;
}
@@ -539,7 +541,7 @@
protected void addElement(String name, PsiElement element) {
element = PyUtil.turnDirIntoInit(element);
if (element instanceof PyElement) {
- result.add((PyElement) element);
+ result.add((PyElement)element);
}
}
};
@@ -557,8 +559,9 @@
@NotNull
public List<PyImportElement> getImportTargets() {
List<PyImportElement> ret = new ArrayList<PyImportElement>();
- List<PyImportStatement> imports = PyPsiUtils.collectStubChildren(this, this.getStub(), PyElementTypes.IMPORT_STATEMENT, PyImportStatement.class);
- for (PyImportStatement one: imports) {
+ List<PyImportStatement> imports =
+ PyPsiUtils.collectStubChildren(this, this.getStub(), PyElementTypes.IMPORT_STATEMENT, PyImportStatement.class);
+ for (PyImportStatement one : imports) {
ContainerUtil.addAll(ret, one.getImportElements());
}
return ret;
@@ -574,7 +577,7 @@
public List<String> getDunderAll() {
final StubElement stubElement = getStub();
if (stubElement instanceof PyFileStub) {
- return ((PyFileStub) stubElement).getDunderAll();
+ return ((PyFileStub)stubElement).getDunderAll();
}
if (!myDunderAllCalculated) {
final List<String> dunderAll = calculateDunderAll();
@@ -600,6 +603,13 @@
private final Map<String, List<String>> myDunderLike = new HashMap<String, List<String>>();
@Override
+ public void visitPyFile(PyFile node) {
+ if (node.getText().contains(PyNames.ALL)) {
+ super.visitPyFile(node);
+ }
+ }
+
+ @Override
public void visitPyTargetExpression(PyTargetExpression node) {
if (PyNames.ALL.equals(node.getName())) {
myFoundDunderAll = true;
@@ -674,7 +684,7 @@
public boolean hasImportFromFuture(FutureFeature feature) {
final StubElement stub = getStub();
if (stub instanceof PyFileStub) {
- return ((PyFileStub) stub).getFutureFeatures().get(feature.ordinal());
+ return ((PyFileStub)stub).getFutureFeatures().get(feature.ordinal());
}
Boolean enabled = myFutureFeatures.get(feature);
if (enabled == null) {
@@ -689,7 +699,7 @@
public String getDeprecationMessage() {
final StubElement stub = getStub();
if (stub instanceof PyFileStub) {
- return ((PyFileStub) stub).getDeprecationMessage();
+ return ((PyFileStub)stub).getDeprecationMessage();
}
return extractDeprecationMessage();
}
@@ -698,13 +708,13 @@
public List<PyImportStatementBase> getImportBlock() {
List<PyImportStatementBase> result = new ArrayList<PyImportStatementBase>();
ASTNode firstImport = getNode().getFirstChildNode();
- while(firstImport != null && !isImport(firstImport, false)) {
+ while (firstImport != null && !isImport(firstImport, false)) {
firstImport = firstImport.getTreeNext();
}
if (firstImport != null) {
result.add(firstImport.getPsi(PyImportStatementBase.class));
ASTNode lastImport = firstImport.getTreeNext();
- while(lastImport != null && isImport(lastImport.getTreeNext(), true)) {
+ while (lastImport != null && isImport(lastImport.getTreeNext(), true)) {
if (isImport(lastImport, false)) {
result.add(lastImport.getPsi(PyImportStatementBase.class));
}
@@ -715,18 +725,28 @@
}
public String extractDeprecationMessage() {
- return PyFunctionImpl.extractDeprecationMessage(getStatements());
+ if (canHaveDeprecationMessage(getText())) {
+ return PyFunctionImpl.extractDeprecationMessage(getStatements());
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean canHaveDeprecationMessage(String text) {
+ return text.contains(PyNames.DEPRECATION_WARNING) || text.contains(PyNames.PENDING_DEPRECATION_WARNING);
}
public boolean calculateImportFromFuture(FutureFeature feature) {
- final List<PyFromImportStatement> fromImports = getFromImports();
- for (PyFromImportStatement fromImport : fromImports) {
- if (fromImport.isFromFuture()) {
- final PyImportElement[] pyImportElements = fromImport.getImportElements();
- for (PyImportElement element : pyImportElements) {
- final QualifiedName qName = element.getImportedQName();
- if (qName != null && qName.matches(feature.toString())) {
- return true;
+ if (getText().contains(feature.toString())) {
+ final List<PyFromImportStatement> fromImports = getFromImports();
+ for (PyFromImportStatement fromImport : fromImports) {
+ if (fromImport.isFromFuture()) {
+ final PyImportElement[] pyImportElements = fromImport.getImportElements();
+ for (PyImportElement element : pyImportElements) {
+ final QualifiedName qName = element.getImportedQName();
+ if (qName != null && qName.matches(feature.toString())) {
+ return true;
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
index cc906b5..132e657 100644
--- a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
+++ b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi.impl;
+import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
@@ -33,7 +34,6 @@
import com.intellij.psi.SingleRootFileViewProvider;
import com.intellij.util.FileContentUtil;
import com.intellij.util.containers.WeakHashMap;
-import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.messages.MessageBus;
import com.jetbrains.python.PythonFileType;
@@ -152,12 +152,12 @@
for (VirtualFile child : fileOrDir.getChildren()) {
if (!child.isDirectory() && PythonFileType.INSTANCE.equals(child.getFileType())) {
- FileBasedIndex.getInstance().requestReindex(child);
+ PushedFilePropertiesUpdater.filePropertiesChanged(child);
}
}
}
- public void afterRootsChanged(@NotNull Project project) {
+ public void afterRootsChanged(@NotNull final Project project) {
Set<Sdk> updatedSdks = new HashSet<Sdk>();
final Module[] modules = ModuleManager.getInstance(project).getModules();
boolean needReparseOpenFiles = false;
@@ -180,23 +180,37 @@
}
}
- private void updateSdkLanguageLevel(Project project, Sdk sdk) {
+ private void updateSdkLanguageLevel(final Project project, final Sdk sdk) {
final LanguageLevel languageLevel = PythonSdkType.getLanguageLevelForSdk(sdk);
final VirtualFile[] files = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
- for (VirtualFile file : files) {
- if (file.isValid()) {
- VirtualFile parent = file.getParent();
- boolean suppressSizeLimit = false;
- if (parent != null && parent.getName().equals(PythonSdkType.SKELETON_DIR_NAME)) {
- suppressSizeLimit = true;
- }
- markRecursively(project, file, languageLevel, suppressSizeLimit);
+ final Application application = ApplicationManager.getApplication();
+ application.executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ application.runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ if (project != null && project.isDisposed()) {
+ return;
+ }
+ for (VirtualFile file : files) {
+ if (file.isValid()) {
+ VirtualFile parent = file.getParent();
+ boolean suppressSizeLimit = false;
+ if (parent != null && parent.getName().equals(PythonSdkType.SKELETON_DIR_NAME)) {
+ suppressSizeLimit = true;
+ }
+ markRecursively(project, file, languageLevel, suppressSizeLimit);
+ }
+ }
+ }
+ });
}
- }
+ });
}
private void markRecursively(final Project project,
- @NotNull VirtualFile file,
+ @NotNull final VirtualFile file,
final LanguageLevel languageLevel,
final boolean suppressSizeLimit) {
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureUsageProcessor.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureUsageProcessor.java
index de4301c..b3190a7 100644
--- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureUsageProcessor.java
+++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureUsageProcessor.java
@@ -110,8 +110,12 @@
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(element.getProject());
StringBuilder builder = buildSignature((PyChangeInfo)changeInfo, call);
- final PyExpression newCall =
- elementGenerator.createExpressionFromText(LanguageLevel.forElement(element), builder.toString());
+ final PyExpression newCall;
+ if (call instanceof PyDecorator) {
+ newCall = elementGenerator.createDecoratorList("@" + builder.toString()).getDecorators()[0];
+ }
+ else
+ newCall = elementGenerator.createExpressionFromText(LanguageLevel.forElement(element), builder.toString());
call.replace(newCall);
return true;
diff --git a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassViewSwingImpl.java b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassViewSwingImpl.java
index aed7301..5a0733f 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassViewSwingImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassViewSwingImpl.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.jetbrains.python.refactoring.classes.extractSuperclass;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
@@ -61,7 +76,7 @@
myFileChooserDescriptor.setRoots(ProjectRootManager.getInstance(project).getContentRoots());
- myFileChooserDescriptor.setIsTreeRootVisible(true);
+ myFileChooserDescriptor.withTreeRootVisible(true);
myTargetDirField = new TextFieldWithBrowseButton();
myTargetDirField
.addBrowseFolderListener(FILE_OR_DIRECTORY, null, project, myFileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
diff --git a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
index c2433df..a582b17 100644
--- a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
@@ -42,6 +42,7 @@
import com.intellij.refactoring.util.RefactoringMessageDialog;
import com.intellij.util.Query;
import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
@@ -95,7 +96,7 @@
invoke(project, editor, (PyTargetExpression)element, refExpr);
}
- public static void invoke(final Project project, final Editor editor, PyTargetExpression local, PyReferenceExpression refExpr) {
+ public static void invoke(final Project project, final Editor editor, final PyTargetExpression local, PyReferenceExpression refExpr) {
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, local)) return;
final HighlightManager highlightManager = HighlightManager.getInstance(project);
@@ -187,6 +188,12 @@
PsiElement[] exprs = new PsiElement[refsToInline.length];
final PyExpression value = prepareValue(def, localName, project);
final PyExpression withParent = PyElementGenerator.getInstance(project).createExpressionFromText("(" + value.getText() + ")");
+ final PsiElement lastChild = def.getLastChild();
+ if (lastChild != null && lastChild.getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT) {
+ final PsiElement parent = def.getParent();
+ if (parent != null) parent.addBefore(lastChild, def);
+ }
+
for (int i = 0, refsToInlineLength = refsToInline.length; i < refsToInlineLength; i++) {
PsiElement element = refsToInline[i];
if (PyReplaceExpressionUtil.isNeedParenthesis((PyExpression)element, value)) {
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
index f479d10..618cf00 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
@@ -44,6 +44,7 @@
import com.intellij.util.Function;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonStringUtil;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
@@ -319,19 +320,19 @@
performActionOnElement(operation);
}
- private boolean breaksStringFormatting(@NotNull String s, @NotNull TextRange range) {
+ private static boolean breaksStringFormatting(@NotNull String s, @NotNull TextRange range) {
return breaksRanges(substitutionsToRanges(filterSubstitutions(parsePercentFormat(s))), range);
}
- private boolean breaksNewStyleStringFormatting(@NotNull String s, @NotNull TextRange range) {
+ private static boolean breaksNewStyleStringFormatting(@NotNull String s, @NotNull TextRange range) {
return breaksRanges(substitutionsToRanges(filterSubstitutions(parseNewStyleFormat(s))), range);
}
- private boolean breaksStringEscaping(@NotNull String s, @NotNull TextRange range) {
+ private static boolean breaksStringEscaping(@NotNull String s, @NotNull TextRange range) {
return breaksRanges(getEscapeRanges(s), range);
}
- private boolean breaksRanges(@NotNull List<TextRange> ranges, @NotNull TextRange range) {
+ private static boolean breaksRanges(@NotNull List<TextRange> ranges, @NotNull TextRange range) {
for (TextRange r : ranges) {
if (range.contains(r)) {
continue;
@@ -396,10 +397,14 @@
}
protected boolean isValidIntroduceContext(PsiElement element) {
- PyDecorator decorator = PsiTreeUtil.getParentOfType(element, PyDecorator.class);
+ final PyDecorator decorator = PsiTreeUtil.getParentOfType(element, PyDecorator.class);
if (decorator != null && PsiTreeUtil.isAncestor(decorator.getCallee(), element, false)) {
return false;
}
+ final PyComprehensionElement comprehension = PsiTreeUtil.getParentOfType(element, PyComprehensionElement.class, true);
+ if (comprehension != null) {
+ return false;
+ }
return PsiTreeUtil.getParentOfType(element, PyParameterList.class) == null;
}
@@ -527,7 +532,7 @@
final Pair<String, String> quotes = detectedQuotes != null ? detectedQuotes : Pair.create("'", "'");
final TextRange range = data.getSecond();
final String substring = range.substring(text);
- myResult.append(quotes.getFirst() + substring + quotes.getSecond());
+ myResult.append(quotes.getFirst()).append(substring).append(quotes.getSecond());
}
else {
ASTNode child = node.getNode().getFirstChildNode();
@@ -550,6 +555,17 @@
}
@Override
+ public void visitPyGeneratorExpression(PyGeneratorExpression node) {
+ final PsiElement firstChild = node.getFirstChild();
+ if (firstChild != null && firstChild.getNode().getElementType() != PyTokenTypes.LPAR) {
+ myResult.append("(").append(node.getText()).append(")");
+ }
+ else {
+ super.visitPyGeneratorExpression(node);
+ }
+ }
+
+ @Override
public void visitElement(PsiElement element) {
if (element.getChildren().length == 0) {
myResult.append(element.getText());
@@ -584,7 +600,7 @@
final PyExpression expression = operation.getInitializer();
final Project project = operation.getProject();
return new WriteCommandAction<PsiElement>(project, expression.getContainingFile()) {
- protected void run(final Result<PsiElement> result) throws Throwable {
+ protected void run(@NotNull final Result<PsiElement> result) throws Throwable {
result.setResult(addDeclaration(operation, declaration));
PyExpression newExpression = createExpression(project, operation.getName(), declaration);
diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDialog.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDialog.java
index 5bc5364..965145c 100644
--- a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDialog.java
+++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor();
descriptor.setRoots(ProjectRootManager.getInstance(project).getContentRoots());
- descriptor.setIsTreeRootVisible(true);
+ descriptor.withTreeRootVisible(true);
myPanel.getBrowseTargetFileButton().addBrowseFolderListener(PyBundle.message("refactoring.move.class.or.function.choose.destination.file.title"),
null, project, descriptor,
diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
index 2d2d12e..a7a96a0 100644
--- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
+++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
@@ -31,6 +31,9 @@
import com.intellij.util.NullableConsumer;
import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.PythonHelpersLocator;
+import com.jetbrains.python.console.PyConsoleProcessHandler;
+import com.jetbrains.python.console.PydevConsoleCommunication;
+import com.jetbrains.python.console.PythonConsoleView;
import com.jetbrains.python.sdk.skeletons.PySkeletonGenerator;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -38,6 +41,7 @@
import java.awt.*;
import java.io.IOException;
+import java.nio.charset.Charset;
import java.util.Collection;
import java.util.List;
@@ -69,7 +73,7 @@
public abstract ProcessOutput runRemoteProcess(@Nullable Project project,
RemoteSdkCredentials data,
- @NotNull PathMappingSettings mappings,
+ @NotNull PathMappingSettings mappings,
String[] command,
@Nullable String workingDir,
boolean askForSudo)
@@ -79,7 +83,7 @@
public abstract RemoteSshProcess createRemoteProcess(@Nullable Project project,
@NotNull PyRemoteSdkCredentials data,
@NotNull PathMappingSettings mappings,
- @NotNull GeneralCommandLine commandLine, boolean allocatePty)
+ @NotNull GeneralCommandLine commandLine, boolean allocatePty)
throws RemoteSdkException;
public abstract boolean editSdk(@NotNull Project project, @NotNull SdkModificator sdkModificator, Collection<Sdk> existingSdks);
@@ -143,6 +147,12 @@
public abstract boolean testConnection(RemoteCredentials credentials);
+ public abstract PyConsoleProcessHandler createConsoleProcessHandler(Process process,
+ PyRemoteSdkCredentials data,
+ PythonConsoleView view,
+ PydevConsoleCommunication consoleCommunication,
+ String commandLine, Charset charset, PathMappingSettings settings);
+
public static class PyRemoteInterpreterExecutionException extends ExecutionException {
public PyRemoteInterpreterExecutionException() {
diff --git a/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java b/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java
index db2b329..b58648e 100644
--- a/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java
+++ b/python/src/com/jetbrains/python/remote/RemoteDebuggableProcessHandler.java
@@ -16,12 +16,10 @@
package com.jetbrains.python.remote;
import com.intellij.remote.RemoteProcessHandlerBase;
-import com.jetbrains.python.debugger.PyDebugProcess;
-import com.jetbrains.python.debugger.PyPositionConverter;
+import com.jetbrains.python.debugger.PositionConverterProvider;
/**
* @author yole
*/
-public interface RemoteDebuggableProcessHandler extends RemoteProcessHandlerBase {
- PyPositionConverter createPositionConverter(PyDebugProcess debugProcess);
+public interface RemoteDebuggableProcessHandler extends RemoteProcessHandlerBase, PositionConverterProvider{
}
diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
index 5d4bb47..216e68c 100644
--- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
@@ -40,6 +40,9 @@
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.roots.*;
+import com.intellij.openapi.roots.impl.libraries.LibraryImpl;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.JarFileSystem;
@@ -52,6 +55,7 @@
import com.jetbrains.python.debugger.PyDebuggerOptionsProvider;
import com.jetbrains.python.facet.LibraryContributingFacet;
import com.jetbrains.python.facet.PythonPathContributingFacet;
+import com.jetbrains.python.library.PythonLibraryType;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonEnvUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
@@ -378,9 +382,6 @@
}
private static void addLibrariesFromModule(Module module, Collection<String> list) {
- if (PlatformUtils.isPyCharm()) {
- return;
- }
final OrderEntry[] entries = ModuleRootManager.getInstance(module).getOrderEntries();
for (OrderEntry entry : entries) {
if (entry instanceof LibraryOrderEntry) {
@@ -390,7 +391,16 @@
continue;
}
for (VirtualFile root : ((LibraryOrderEntry)entry).getRootFiles(OrderRootType.CLASSES)) {
- addToPythonPath(root, list);
+ final Library library = ((LibraryOrderEntry)entry).getLibrary();
+ if (!PlatformUtils.isPyCharm()) {
+ addToPythonPath(root, list);
+ }
+ else if (library instanceof LibraryImpl) {
+ final PersistentLibraryKind<?> kind = ((LibraryImpl)library).getKind();
+ if (kind == PythonLibraryType.getInstance().getKind()) {
+ addToPythonPath(root, list);
+ }
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/run/PythonConfigurationType.java b/python/src/com/jetbrains/python/run/PythonConfigurationType.java
index 6d2e26a..0821452 100644
--- a/python/src/com/jetbrains/python/run/PythonConfigurationType.java
+++ b/python/src/com/jetbrains/python/run/PythonConfigurationType.java
@@ -17,8 +17,8 @@
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.ConfigurationTypeUtil;
import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import icons.PythonIcons;
import org.jetbrains.annotations.NonNls;
@@ -34,13 +34,7 @@
private final PythonConfigurationFactory myFactory = new PythonConfigurationFactory(this);
public static PythonConfigurationType getInstance() {
- for(ConfigurationType configType: Extensions.getExtensions(CONFIGURATION_TYPE_EP)) {
- if (configType instanceof PythonConfigurationType) {
- return (PythonConfigurationType) configType;
- }
- }
- assert false;
- return null;
+ return ConfigurationTypeUtil.findConfigurationType(PythonConfigurationType.class);
}
private static class PythonConfigurationFactory extends PythonConfigurationFactoryBase {
diff --git a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
index 3b0392f..da041f9 100644
--- a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
+++ b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,8 +64,8 @@
chooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) {
@Override
- protected void onFileChoosen(@NotNull VirtualFile chosenFile) {
- super.onFileChoosen(chosenFile);
+ protected void onFileChosen(@NotNull VirtualFile chosenFile) {
+ super.onFileChosen(chosenFile);
myCommonOptionsForm.setWorkingDirectory(chosenFile.getParent().getPath());
}
};
diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
index 0a9d63a..c3516dc 100644
--- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
+++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.PathChooserDialog;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
@@ -36,7 +35,6 @@
import com.intellij.openapi.ui.FixedSizeButton;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -251,9 +249,7 @@
final PythonSdkType sdkType = PythonSdkType.getInstance();
final FileChooserDescriptor descriptor = sdkType.getHomeChooserDescriptor();
- if (SystemInfo.isMac) {
- descriptor.putUserData(PathChooserDialog.NATIVE_MAC_CHOOSER_SHOW_HIDDEN_FILES, Boolean.TRUE);
- }
+
String suggestedPath = sdkType.suggestHomePath();
VirtualFile suggestedDir = suggestedPath == null
? null
diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
index d8a2c2f..60a4c5b 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
@@ -17,9 +17,12 @@
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessOutput;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -54,6 +57,8 @@
// Windows EOF marker, Ctrl+Z
public static final int SUBSTITUTE = 26;
+ private static final String REMOTE_SOURCES_DIR_NAME = "remote_sources";
+
private PySdkUtil() {
// explicitly none
}
@@ -106,12 +111,11 @@
* Executes a process and returns its stdout and stderr outputs as lists of lines.
* Waits for process for possibly limited duration.
*
- *
- * @param homePath process run directory
- * @param command command to execute and its arguments
- * @param addEnv items are prepended to same-named values of inherited process environment.
- * @param timeout how many milliseconds to wait until the process terminates; non-positive means infinity.
- * @param stdin the data to write to the process standard input stream
+ * @param homePath process run directory
+ * @param command command to execute and its arguments
+ * @param addEnv items are prepended to same-named values of inherited process environment.
+ * @param timeout how many milliseconds to wait until the process terminates; non-positive means infinity.
+ * @param stdin the data to write to the process standard input stream
* @param needEOFMarker
* @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null.
*/
@@ -223,7 +227,7 @@
if (virtualFile != null) {
final Sdk sdk = PythonSdkType.getSdk(element);
if (sdk != null) {
- final VirtualFile skeletonsDir = PythonSdkType.findSkeletonsDir(sdk);
+ final VirtualFile skeletonsDir = findSkeletonsDir(sdk);
if (skeletonsDir != null && VfsUtilCore.isAncestor(skeletonsDir, virtualFile, false)) {
return true;
}
@@ -232,4 +236,36 @@
}
return false;
}
+
+ public static String getRemoteSourcesLocalPath(String sdkHome) {
+ String sep = File.separator;
+
+ String basePath = PathManager.getSystemPath();
+ return basePath +
+ File.separator +
+ REMOTE_SOURCES_DIR_NAME +
+ sep +
+ FileUtil.toSystemIndependentName(sdkHome).hashCode() +
+ sep;
+ }
+
+ @Nullable
+ public static VirtualFile findSkeletonsDir(@NotNull final Sdk sdk) {
+ return findLibraryDir(sdk, PythonSdkType.SKELETON_DIR_NAME, PythonSdkType.BUILTIN_ROOT_TYPE);
+ }
+
+ @Nullable
+ public static VirtualFile findRemoteLibrariesDir(@NotNull final Sdk sdk) {
+ return findLibraryDir(sdk, REMOTE_SOURCES_DIR_NAME, OrderRootType.CLASSES);
+ }
+
+ private static VirtualFile findLibraryDir(Sdk sdk, String dirName, OrderRootType rootType) {
+ final VirtualFile[] virtualFiles = sdk.getRootProvider().getFiles(rootType);
+ for (VirtualFile virtualFile : virtualFiles) {
+ if (virtualFile.isValid() && virtualFile.getPath().contains(dirName)) {
+ return virtualFile;
+ }
+ }
+ return null;
+ }
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
index 7148c3d..ad860f7 100644
--- a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java
@@ -34,6 +34,7 @@
@SuppressWarnings("SpellCheckingInspection") public static final String PYTHONPATH = "PYTHONPATH";
@SuppressWarnings("SpellCheckingInspection") public static final String PYTHONUNBUFFERED = "PYTHONUNBUFFERED";
@SuppressWarnings("SpellCheckingInspection") public static final String PYTHONIOENCODING = "PYTHONIOENCODING";
+ @SuppressWarnings("SpellCheckingInspection") public static final String IPYTHONENABLE = "IPYTHONENABLE";
private PythonEnvUtil() { }
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
index 7a6b2db..923629c 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
@@ -56,22 +56,37 @@
private static final String REMOTE = "Add Remote";
private static final String VIRTUALENV = "Create VirtualEnv";
private static final String MORE = "More...";
+ private boolean myNewProject;
public static void show(final Project project,
final Sdk[] existingSdks,
- DialogWrapper moreDialog,
+ @Nullable final DialogWrapper moreDialog,
JComponent ownerComponent, final Point popupPoint,
final NullableConsumer<Sdk> callback) {
+ show(project, existingSdks, moreDialog, ownerComponent, popupPoint, callback, false);
- final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, moreDialog, ownerComponent, existingSdks, callback);
+ }
+
+ public static void show(final Project project,
+ final Sdk[] existingSdks,
+ @Nullable final DialogWrapper moreDialog,
+ JComponent ownerComponent, final Point popupPoint,
+ final NullableConsumer<Sdk> callback, boolean isNewProject) {
+ final PythonSdkDetailsStep sdkHomesStep = new PythonSdkDetailsStep(project, moreDialog, ownerComponent, existingSdks, callback);
+ sdkHomesStep.setNewProject(isNewProject);
final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep);
Dimension size = new JLabel(VIRTUALENV, EmptyIcon.ICON_16, SwingConstants.LEFT).getMinimumSize();
- final int height = size.height * 5 + 5;
+ int componentNum = getAvailableOptions(moreDialog != null).size() + 1;
+ int height = size.height * componentNum + 2*componentNum;
popup.setSize(new Dimension(size.width, height));
popup.setMinimumSize(new Dimension(size.width, height));
popup.showInScreenCoordinates(ownerComponent, popupPoint);
}
+ private void setNewProject(boolean isNewProject) {
+ myNewProject = isNewProject;
+ }
+
public PythonSdkDetailsStep(@Nullable final Project project,
@Nullable final DialogWrapper moreDialog, @NotNull final Component ownerComponent,
@NotNull final Sdk[] existingSdks,
@@ -151,7 +166,12 @@
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath()));
((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData);
}
- ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject);
+ if (myNewProject) {
+ ((PythonSdkAdditionalData)additionalData).associateWithNewProject();
+ }
+ else {
+ ((PythonSdkAdditionalData)additionalData).associateWithProject(myProject);
+ }
}
myCallback.consume(sdk);
}
@@ -195,7 +215,7 @@
@Override
public void canceled() {
- if (getFinalRunnable() == null)
+ if (getFinalRunnable() == null && myMore != null)
Disposer.dispose(myMore.getDisposable());
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index c369f1c3..d3301da 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -241,7 +241,8 @@
@Override
public FileChooserDescriptor getHomeChooserDescriptor() {
final boolean is_windows = SystemInfo.isWindows;
- FileChooserDescriptor result = new FileChooserDescriptor(true, false, false, false, false, false) {
+ return new FileChooserDescriptor(true, false, false, false, false, false) {
+ @Override
public void validateSelectedFiles(VirtualFile[] files) throws Exception {
if (files.length != 0) {
if (!isValidSdkHome(files[0].getPath())) {
@@ -268,9 +269,7 @@
}
return super.isFileVisible(file, showHiddenFiles);
}
- };
- result.setTitle(PyBundle.message("sdk.select.path"));
- return result;
+ }.withTitle(PyBundle.message("sdk.select.path")).withShowHiddenFiles(SystemInfo.isUnix);
}
public boolean supportsCustomCreateUI() {
@@ -288,6 +287,7 @@
public void consume(@Nullable Sdk sdk) {
if (sdk != null) {
sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference<Component>(parentComponent));
+ sdkCreatedCallback.consume(sdk);
}
}
});
@@ -451,22 +451,15 @@
public static String findSkeletonsPath(Sdk sdk) {
final String[] urls = sdk.getRootProvider().getUrls(BUILTIN_ROOT_TYPE);
for (String url : urls) {
- if (url.contains(SKELETON_DIR_NAME)) {
+ if (isSkeletonsPath(url)) {
return VfsUtilCore.urlToPath(url);
}
}
return null;
}
- @Nullable
- public static VirtualFile findSkeletonsDir(@NotNull final Sdk sdk) {
- final VirtualFile[] virtualFiles = sdk.getRootProvider().getFiles(BUILTIN_ROOT_TYPE);
- for (VirtualFile virtualFile : virtualFiles) {
- if (virtualFile.isValid() && virtualFile.getPath().contains(SKELETON_DIR_NAME)) {
- return virtualFile;
- }
- }
- return null;
+ public static boolean isSkeletonsPath(String path) {
+ return path.contains(SKELETON_DIR_NAME);
}
@NonNls
@@ -500,6 +493,11 @@
setupSdkPaths(sdk, project, ownerComponent);
}
+ @Override
+ public boolean setupSdkPaths(Sdk sdk, SdkModel sdkModel) {
+ return true; // run setupSdkPaths only once (from PythonSdkDetailsStep). Skip this from showCustomCreateUI
+ }
+
public static void setupSdkPaths(Sdk sdk, @Nullable Project project, @Nullable Component ownerComponent) {
final SdkModificator sdkModificator = sdk.getSdkModificator();
final boolean success = setupSdkPaths(project, ownerComponent, sdk, sdkModificator);
@@ -577,8 +575,8 @@
Application application = ApplicationManager.getApplication();
boolean not_in_unit_test_mode = (application != null && !application.isUnitTestMode());
- String bin_path = sdkModificator.getHomePath();
- assert bin_path != null;
+ String sdkHome = sdkModificator.getHomePath();
+ assert sdkHome != null;
final String sep = File.separator;
// we have a number of lib dirs, those listed in python's sys.path
if (indicator != null) {
@@ -586,7 +584,7 @@
}
// Add folders from sys.path
if (!PySdkUtil.isRemote(sdk)) { //no sense to add roots of remote sdk
- final List<String> paths = getSysPath(bin_path);
+ final List<String> paths = getSysPath(sdkHome);
if (paths.size() > 0) {
// add every path as root.
for (String path : paths) {
@@ -597,13 +595,15 @@
addSdkRoot(sdkModificator, path);
}
}
+ } else {
+ addRemoteLibrariesRoot(sdkModificator, sdkHome);
}
PyUserSkeletonsUtil.addUserSkeletonsRoot(sdkModificator);
- addSkeletonsRoot(sdkModificator, bin_path);
+ addSkeletonsRoot(sdkModificator, sdkHome);
if (not_in_unit_test_mode) {
- File venv_root = getVirtualEnvRoot(bin_path);
+ File venv_root = getVirtualEnvRoot(sdkHome);
if (venv_root != null && venv_root.isDirectory()) {
File lib_root = new File(venv_root, "lib");
if (lib_root.isDirectory()) {
@@ -639,14 +639,22 @@
}
}
- private static void addSkeletonsRoot(@NotNull SdkModificator sdkModificator, String bin_path) {
- @NonNls final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), bin_path);
+ private static void addSkeletonsRoot(@NotNull SdkModificator sdkModificator, String sdkHome) {
+ @NonNls final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), sdkHome);
new File(skeletonsPath).mkdirs();
final VirtualFile builtins_root = LocalFileSystem.getInstance().refreshAndFindFileByPath(skeletonsPath);
assert builtins_root != null : "Cannot find skeletons path " + skeletonsPath + " in VFS";
sdkModificator.addRoot(builtins_root, BUILTIN_ROOT_TYPE);
}
+ private static void addRemoteLibrariesRoot(@NotNull SdkModificator sdkModificator, String sdkHome) {
+ @NonNls final String librariesRoot = PySdkUtil.getRemoteSourcesLocalPath(sdkHome);
+ new File(librariesRoot).mkdirs();
+ final VirtualFile remoteLibraries = LocalFileSystem.getInstance().refreshAndFindFileByPath(librariesRoot);
+ assert remoteLibraries != null : "Cannot find remote libraries path " + librariesRoot + " in VFS";
+ sdkModificator.addRoot(remoteLibraries, OrderRootType.CLASSES);
+ }
+
protected static void addHardcodedPaths(SdkModificator sdkModificator) {
// Add python-django installed as package in Linux
// NOTE: fragile and arbitrary
@@ -821,7 +829,7 @@
if (venvLibDir != null && VfsUtilCore.isAncestor(venvLibDir, vFile, false)) {
return isNotSitePackages(vFile, venvLibDir);
}
- final VirtualFile skeletonsDir = findSkeletonsDir(pythonSdk);
+ final VirtualFile skeletonsDir = PySdkUtil.findSkeletonsDir(pythonSdk);
if (skeletonsDir != null &&
Comparing.equal(vFile.getParent(), skeletonsDir)) { // note: this will pick up some of the binary libraries not in packages
return true;
@@ -929,13 +937,6 @@
return null;
}
- @Nullable
- public static String getExecutablePath(@NotNull final Sdk sdk, @NotNull String name) {
- final String homeDirectory = sdk.getHomePath();
- if (homeDirectory == null) return null;
- return getExecutablePath(homeDirectory, name);
- }
-
private static String[] getBinaryNames() {
if (SystemInfo.isUnix) {
return UNIX_BINARY_NAMES;
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
index db841c2..28d8e51 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.sdk.skeletons;
+import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.notification.Notification;
@@ -37,7 +38,9 @@
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
+import com.intellij.util.Function;
import com.intellij.util.SmartList;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.ZipUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
@@ -223,42 +226,33 @@
}
private static String calculateExtraSysPath(@NotNull final Sdk sdk, @Nullable final String skeletonsPath) {
- File canonicalSkeleton = null;
- File canonicalUserSkeletonsDir = null;
+ final File skeletons = skeletonsPath != null ? new File(skeletonsPath) : null;
- try {
- if (skeletonsPath != null) {
- canonicalSkeleton = new File(skeletonsPath).getCanonicalFile();
- }
- final VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory();
- if (userSkeletonsDir != null) {
- canonicalUserSkeletonsDir = new File(userSkeletonsDir.getPath());
- }
- }catch (final IOException e) {
- LOG.error("Error getting real paths", e);
- }
+ final VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory();
+ final File userSkeletons = userSkeletonsDir != null ? new File(userSkeletonsDir.getPath()) : null;
+ final VirtualFile remoteSourcesDir = PySdkUtil.findRemoteLibrariesDir(sdk);
+ final File remoteSources = remoteSourcesDir != null ? new File(remoteSourcesDir.getPath()) : null;
final VirtualFile[] classDirs = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
- final StringBuilder builder = new StringBuilder("");
- int countAddedPaths = 0;
- for (final VirtualFile file : classDirs) {
- if (countAddedPaths > 0) {
- builder.append(File.pathSeparator);
- }
- if (file.isInLocalFileSystem()) {
- // We compare canonical files, not strings because "c:/some/folder" equals "c:\\some\\bin\\..\\folder\\"
- final File canonicalFile = new File(file.getPath());
- if (canonicalFile.exists() && !canonicalFile.equals(canonicalSkeleton) && !canonicalFile.equals(canonicalUserSkeletonsDir)) {
- final String pathname = file.getPath();
- builder.append(pathname);
- countAddedPaths += 1;
- }
- }
- }
- builder.append("");
- return builder.toString();
+ return Joiner.on(File.pathSeparator).join(ContainerUtil.mapNotNull(classDirs, new Function<VirtualFile, Object>() {
+
+ @Override
+ public Object fun(VirtualFile file) {
+ if (file.isInLocalFileSystem()) {
+ // We compare canonical files, not strings because "c:/some/folder" equals "c:\\some\\bin\\..\\folder\\"
+ final File canonicalFile = new File(file.getPath());
+ if (canonicalFile.exists() &&
+ !FileUtil.filesEqual(canonicalFile, skeletons) &&
+ !FileUtil.filesEqual(canonicalFile, userSkeletons) &&
+ !FileUtil.filesEqual(canonicalFile, remoteSources)) {
+ return file.getPath();
+ }
+ }
+ return null;
+ }
+ }));
}
/**
@@ -279,7 +273,7 @@
}
public List<String> regenerateSkeletons(@Nullable SkeletonVersionChecker cachedChecker,
- @Nullable Ref<Boolean> migrationFlag) throws InvalidSdkException {
+ @Nullable Ref<Boolean> migrationFlag) throws InvalidSdkException {
final List<String> errorList = new SmartList<String>();
final String homePath = mySdk.getHomePath();
final String skeletonsPath = getSkeletonsPath();
@@ -411,7 +405,7 @@
}
if (PySdkUtil.isRemote(mySdk)) {
try {
- ((PyPackageManagerImpl) PyPackageManager.getInstance(mySdk)).loadPackages();
+ ((PyPackageManagerImpl)PyPackageManager.getInstance(mySdk)).loadPackages();
}
catch (PyExternalProcessException e) {
// ignore - already logged
diff --git a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java
index 5d1a126..8a27d8a 100644
--- a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java
+++ b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java
@@ -246,7 +246,8 @@
}
return getPluralTitle() + " in " + name;
case TEST_FOLDER:
- return getPluralTitle() + " in " + FileUtil.toSystemDependentName(myFolderName);
+ String folderName = new File(myFolderName).getName();
+ return getPluralTitle() + " in " + folderName;
case TEST_FUNCTION:
return getTitle() + " " + myMethodName;
default:
diff --git a/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java
index 8c28e08..ccf048b 100644
--- a/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java
+++ b/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java
@@ -21,6 +21,7 @@
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.openapi.module.Module;
@@ -41,6 +42,8 @@
import com.jetbrains.python.facet.PythonFacetSettings;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.run.PythonRunConfigurationProducer;
+import com.jetbrains.python.testing.unittest.PythonUnitTestRunConfiguration;
+import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -90,7 +93,7 @@
return confType == AbstractPythonTestRunConfiguration.TestType.TEST_FUNCTION &&
methodName.equals(pyFunction.getName()) && isTestFileEquals;
}
- else if (pyFunction.getContainingClass() != null) {
+ else {
final String className = configuration.getClassName();
return confType == AbstractPythonTestRunConfiguration.TestType.TEST_METHOD &&
@@ -206,7 +209,7 @@
}
protected boolean isTestFolder(@NotNull final VirtualFile virtualFile, @NotNull final Project project) {
- final String name = virtualFile.getName();
+ @NonNls final String name = virtualFile.getName();
final HashSet<VirtualFile> roots = Sets.newHashSet();
final Module[] modules = ModuleManager.getInstance(project).getModules();
for (Module module : modules) {
@@ -258,6 +261,11 @@
@Override
public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) {
+ final RunConfiguration configuration = self.getConfiguration();
+ if (configuration instanceof PythonUnitTestRunConfiguration &&
+ ((PythonUnitTestRunConfiguration)configuration).getTestType() == AbstractPythonTestRunConfiguration.TestType.TEST_FOLDER) {
+ return true;
+ }
return other.isProducedBy(PythonTestConfigurationProducer.class) || other.isProducedBy(PythonRunConfigurationProducer.class);
}
}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java
index b74d562..0770a17 100644
--- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java
+++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.testing.attest;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.io.FileUtil;
import com.jetbrains.python.testing.PythonTestCommandLineStateBase;
import java.util.ArrayList;
@@ -41,24 +42,27 @@
protected List<String> getTestSpecs() {
List<String> specs = new ArrayList<String>();
+ final String scriptName = FileUtil.toSystemDependentName(myConfig.getScriptName());
switch (myConfig.getTestType()) {
case TEST_SCRIPT:
- specs.add(myConfig.getScriptName());
+ specs.add(scriptName);
break;
case TEST_CLASS:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName());
+ specs.add(scriptName + "::" + myConfig.getClassName());
break;
case TEST_METHOD:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
+ specs.add(scriptName + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
break;
case TEST_FOLDER:
- if (!myConfig.getPattern().isEmpty())
- specs.add(myConfig.getFolderName() + "/" + ";" + myConfig.getPattern());
+ final String folderName = FileUtil.toSystemDependentName(myConfig.getFolderName() + "/");
+ if (!myConfig.getPattern().isEmpty()) {
+ specs.add(folderName + ";" + myConfig.getPattern());
+ }
else
- specs.add(myConfig.getFolderName() + "/");
+ specs.add(folderName);
break;
case TEST_FUNCTION:
- specs.add(myConfig.getScriptName() + "::::" + myConfig.getMethodName());
+ specs.add(scriptName + "::::" + myConfig.getMethodName());
break;
default:
throw new IllegalArgumentException("Unknown test type: " + myConfig.getTestType());
diff --git a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java
index b5b2759..4d94ddf 100644
--- a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java
+++ b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java
@@ -19,6 +19,7 @@
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.jetbrains.python.testing.PythonTestCommandLineStateBase;
@@ -45,21 +46,22 @@
protected List<String> getTestSpecs() {
List<String> specs = new ArrayList<String>();
+ final String scriptName = FileUtil.toSystemDependentName(myConfig.getScriptName());
switch (myConfig.getTestType()) {
case TEST_SCRIPT:
- specs.add(myConfig.getScriptName());
+ specs.add(scriptName);
break;
case TEST_CLASS:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName());
+ specs.add(scriptName + "::" + myConfig.getClassName());
break;
case TEST_METHOD:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
+ specs.add(scriptName + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
break;
case TEST_FOLDER:
- specs.add(myConfig.getFolderName() + "/");
+ specs.add(FileUtil.toSystemDependentName(myConfig.getFolderName() + "/"));
break;
case TEST_FUNCTION:
- specs.add(myConfig.getScriptName() + "::::" + myConfig.getMethodName());
+ specs.add(scriptName + "::::" + myConfig.getMethodName());
break;
default:
throw new IllegalArgumentException("Unknown test type: " + myConfig.getTestType());
@@ -72,7 +74,7 @@
ParamsGroup script_params = cmd.getParametersList().getParamsGroup(GROUP_SCRIPT);
assert script_params != null;
if (myConfig.useParam() && !StringUtil.isEmptyOrSpaces(myConfig.getParams()))
- script_params.addParameter(myConfig.getParams());
+ script_params.addParametersString(myConfig.getParams());
}
}
diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java
index 572cfde..3637f37 100644
--- a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java
+++ b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java
@@ -67,8 +67,7 @@
assert script_params != null;
String params = myConfiguration.getParams();
if (!StringUtil.isEmptyOrSpaces(params)) {
- for (String p : StringUtil.splitHonorQuotes(params, ' '))
- script_params.addParameter(p);
+ script_params.addParametersString(params);
}
String keywords = myConfiguration.getKeywords();
diff --git a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
index 4d94d36..c3fb85b 100644
--- a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
+++ b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
@@ -65,11 +65,12 @@
specs.add(scriptName + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
break;
case TEST_FOLDER:
+ final String folderName = FileUtil.toSystemDependentName(myConfig.getFolderName() + "/");
if (!StringUtil.isEmpty(myConfig.getPattern()) && myConfig.usePattern()) {
- specs.add(myConfig.getFolderName() + "/" + ";" + myConfig.getPattern());
+ specs.add(folderName + ";" + myConfig.getPattern());
}
else {
- specs.add(myConfig.getFolderName() + "/");
+ specs.add(folderName);
}
break;
case TEST_FUNCTION:
diff --git a/python/src/com/jetbrains/python/toolbox/FP.java b/python/src/com/jetbrains/python/toolbox/FP.java
index 148cfe3..2fc2ef59 100644
--- a/python/src/com/jetbrains/python/toolbox/FP.java
+++ b/python/src/com/jetbrains/python/toolbox/FP.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -238,9 +238,9 @@
}
public Pair<R1, R2> next() {
- if (one_iter.hasNext() && two_iter.hasNext()) return new Pair<R1, R2>(one_iter.next(), two_iter.next());
- if (fill1 && two_iter.hasNext()) return new Pair<R1, R2>(filler1, two_iter.next());
- if (fill2 && one_iter.hasNext()) return new Pair<R1, R2>(one_iter.next(), filler2);
+ if (one_iter.hasNext() && two_iter.hasNext()) return Pair.create(one_iter.next(), two_iter.next());
+ if (fill1 && two_iter.hasNext()) return Pair.create(filler1, two_iter.next());
+ if (fill2 && one_iter.hasNext()) return Pair.create(one_iter.next(), filler2);
throw new NoSuchElementException();
}
};
diff --git a/python/src/com/jetbrains/python/validation/ReturnAnnotator.java b/python/src/com/jetbrains/python/validation/ReturnAnnotator.java
index 93a877b..b23cb8c 100644
--- a/python/src/com/jetbrains/python/validation/ReturnAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/ReturnAnnotator.java
@@ -16,28 +16,25 @@
package com.jetbrains.python.validation;
import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
/**
- * Highlights incorrect return statements: 'return' and 'yield' outside functions, returning values from generators;
+ * Highlights incorrect return statements: 'return' and 'yield' outside functions, returning values from generators.
*/
public class ReturnAnnotator extends PyAnnotator {
public void visitPyReturnStatement(final PyReturnStatement node) {
PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class, false, PyClass.class);
if (function == null) {
getHolder().createErrorAnnotation(node, "'return' outside of function");
- return;
}
}
public void visitPyYieldExpression(final PyYieldExpression node) {
- if (PsiTreeUtil.getParentOfType(node, PyFunction.class, false, PyClass.class) == null) {
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(node);
+ if (!(owner instanceof PyFunction || owner instanceof PyLambdaExpression)) {
getHolder().createErrorAnnotation(node, "'yield' outside of function");
}
- /* this is now allowed in python 2.5
- if (node.getContainingElement(PyTryFinallyStatement.class) != null) {
- getHolder().createErrorAnnotation(node, "'yield' not allowed in a 'try' block with a 'finally' clause");
- }
- */
}
}
diff --git a/python/testData/console/indent10.after.py b/python/testData/console/indent10.after.py
new file mode 100644
index 0000000..73b1b83
--- /dev/null
+++ b/python/testData/console/indent10.after.py
@@ -0,0 +1,15 @@
+x = '''Multiline starts;
+ next line with indent;
+ next line with indent;
+ multiline ends'''
+x = '''Multiline starts;
+ first
+ second
+ third
+ fourth
+ fifth
+ multiline ends'''
+x = '''Multiline starts;
+ #line
+ #line
+ multiline ends'''
\ No newline at end of file
diff --git a/python/testData/console/indent10.py b/python/testData/console/indent10.py
new file mode 100644
index 0000000..7982900
--- /dev/null
+++ b/python/testData/console/indent10.py
@@ -0,0 +1,17 @@
+x = '''Multiline starts;
+ next line with indent;
+ next line with indent;
+ multiline ends'''
+
+x = '''Multiline starts;
+ first
+ second
+ third
+ fourth
+ fifth
+ multiline ends'''
+
+x = '''Multiline starts;
+ #line
+ #line
+ multiline ends'''
\ No newline at end of file
diff --git a/python/testData/console/indent11.after.py b/python/testData/console/indent11.after.py
new file mode 100644
index 0000000..6dcae01
--- /dev/null
+++ b/python/testData/console/indent11.after.py
@@ -0,0 +1,4 @@
+print('first',#comment
+ 'second', #comment
+ #inline comment
+ 'third')
\ No newline at end of file
diff --git a/python/testData/console/indent11.py b/python/testData/console/indent11.py
new file mode 100644
index 0000000..503e56d
--- /dev/null
+++ b/python/testData/console/indent11.py
@@ -0,0 +1,4 @@
+ print('first',#comment
+ 'second', #comment
+ #inline comment
+ 'third')
\ No newline at end of file
diff --git a/python/testData/console/indent12.after.py b/python/testData/console/indent12.after.py
new file mode 100644
index 0000000..0e74eb5
--- /dev/null
+++ b/python/testData/console/indent12.after.py
@@ -0,0 +1,3 @@
+def foo():
+ print(
+ '12345')
\ No newline at end of file
diff --git a/python/testData/console/indent12.py b/python/testData/console/indent12.py
new file mode 100644
index 0000000..5633484
--- /dev/null
+++ b/python/testData/console/indent12.py
@@ -0,0 +1,3 @@
+ def foo():
+ print(
+ '12345')
\ No newline at end of file
diff --git a/python/testData/console/indent13.after.py b/python/testData/console/indent13.after.py
new file mode 100644
index 0000000..2fb2a43
--- /dev/null
+++ b/python/testData/console/indent13.after.py
@@ -0,0 +1,3 @@
+def foo():
+ return [i**2 for i in
+ range(1,100,1)]
\ No newline at end of file
diff --git a/python/testData/console/indent13.py b/python/testData/console/indent13.py
new file mode 100644
index 0000000..2fb2a43
--- /dev/null
+++ b/python/testData/console/indent13.py
@@ -0,0 +1,3 @@
+def foo():
+ return [i**2 for i in
+ range(1,100,1)]
\ No newline at end of file
diff --git a/python/testData/console/indent14.after.py b/python/testData/console/indent14.after.py
new file mode 100644
index 0000000..a0ce025
--- /dev/null
+++ b/python/testData/console/indent14.after.py
@@ -0,0 +1,5 @@
+print 'One, two. How are you?\
+ Three, four. Who\'s at the door?\
+ Five, six. My name is Fix.\
+ Seven, eght. Sorry, I\'m late.\
+ Nine, ten. Say it again.'
\ No newline at end of file
diff --git a/python/testData/console/indent14.py b/python/testData/console/indent14.py
new file mode 100644
index 0000000..38b1127
--- /dev/null
+++ b/python/testData/console/indent14.py
@@ -0,0 +1,5 @@
+ print 'One, two. How are you?\
+ Three, four. Who\'s at the door?\
+ Five, six. My name is Fix.\
+ Seven, eght. Sorry, I\'m late.\
+ Nine, ten. Say it again.'
\ No newline at end of file
diff --git a/python/testData/console/indent15.after.py b/python/testData/console/indent15.after.py
new file mode 100644
index 0000000..8af375a
--- /dev/null
+++ b/python/testData/console/indent15.after.py
@@ -0,0 +1,3 @@
+def foo():
+ print '4'
+ print '8'
\ No newline at end of file
diff --git a/python/testData/console/indent15.py b/python/testData/console/indent15.py
new file mode 100644
index 0000000..8af375a
--- /dev/null
+++ b/python/testData/console/indent15.py
@@ -0,0 +1,3 @@
+def foo():
+ print '4'
+ print '8'
\ No newline at end of file
diff --git a/python/testData/console/indent16.after.py b/python/testData/console/indent16.after.py
new file mode 100644
index 0000000..cf0bcd33
--- /dev/null
+++ b/python/testData/console/indent16.after.py
@@ -0,0 +1,5 @@
+print 'print'
+def foo():
+ print 'foo'
+def bar():
+ print 'bar'
\ No newline at end of file
diff --git a/python/testData/console/indent16.py b/python/testData/console/indent16.py
new file mode 100644
index 0000000..6d31063
--- /dev/null
+++ b/python/testData/console/indent16.py
@@ -0,0 +1,7 @@
+ print 'print'
+
+ def foo():
+ print 'foo'
+
+ def bar():
+ print 'bar'
\ No newline at end of file
diff --git a/python/testData/console/indent2.after.py b/python/testData/console/indent2.after.py
index 6b3a39b..c8a3084 100644
--- a/python/testData/console/indent2.after.py
+++ b/python/testData/console/indent2.after.py
@@ -1,4 +1,4 @@
for x in range(1, 10):
print x
-print 1
-print 2
\ No newline at end of file
+ print 1
+ print 2
\ No newline at end of file
diff --git a/python/testData/console/indent4.after.py b/python/testData/console/indent4.after.py
index 0c4dd41..27304b2 100644
--- a/python/testData/console/indent4.after.py
+++ b/python/testData/console/indent4.after.py
@@ -1,5 +1,5 @@
print 1
-for j in range(0, 2):
- for i in range(1, 10):
- print i
- print '!'
\ No newline at end of file
+ for j in range(0, 2):
+ for i in range(1, 10):
+ print i
+ print '!'
\ No newline at end of file
diff --git a/python/testData/console/indent8.after.py b/python/testData/console/indent8.after.py
new file mode 100644
index 0000000..7b04345
--- /dev/null
+++ b/python/testData/console/indent8.after.py
@@ -0,0 +1,4 @@
+def foo():
+ print 'foo'
+ #comment with indent
+ print 'bar'
\ No newline at end of file
diff --git a/python/testData/console/indent8.py b/python/testData/console/indent8.py
new file mode 100644
index 0000000..7b04345
--- /dev/null
+++ b/python/testData/console/indent8.py
@@ -0,0 +1,4 @@
+def foo():
+ print 'foo'
+ #comment with indent
+ print 'bar'
\ No newline at end of file
diff --git a/python/testData/console/indent9.after.py b/python/testData/console/indent9.after.py
new file mode 100644
index 0000000..2077284
--- /dev/null
+++ b/python/testData/console/indent9.after.py
@@ -0,0 +1,7 @@
+class foo:
+ """
+ Some docstring here.
+ Another string.
+ """
+ def bar(self):
+ print "hello"
\ No newline at end of file
diff --git a/python/testData/console/indent9.py b/python/testData/console/indent9.py
new file mode 100644
index 0000000..2077284
--- /dev/null
+++ b/python/testData/console/indent9.py
@@ -0,0 +1,7 @@
+class foo:
+ """
+ Some docstring here.
+ Another string.
+ """
+ def bar(self):
+ print "hello"
\ No newline at end of file
diff --git a/python/testData/highlighting/yieldInDefaultValue.py b/python/testData/highlighting/yieldInDefaultValue.py
new file mode 100644
index 0000000..1d2482c
--- /dev/null
+++ b/python/testData/highlighting/yieldInDefaultValue.py
@@ -0,0 +1,2 @@
+def f(x=(<error descr="'yield' outside of function">yield 10</error>)):
+ return x
diff --git a/python/testData/highlighting/yieldInLambda.py b/python/testData/highlighting/yieldInLambda.py
new file mode 100644
index 0000000..72ecd04
--- /dev/null
+++ b/python/testData/highlighting/yieldInLambda.py
@@ -0,0 +1 @@
+g = lambda: (yield 10)
diff --git a/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py b/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
index b75341f..c53ac2b 100644
--- a/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
+++ b/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
@@ -73,3 +73,9 @@
a( 1024*1024)
+
+def f1(value=-1):
+ print(value)
+
+def f2():
+ f1(value =-2)
\ No newline at end of file
diff --git a/python/testData/inspections/RedundantParenthesesParenthesizedExpression.py b/python/testData/inspections/RedundantParenthesesParenthesizedExpression.py
new file mode 100644
index 0000000..c068255
--- /dev/null
+++ b/python/testData/inspections/RedundantParenthesesParenthesizedExpression.py
@@ -0,0 +1,2 @@
+if ((1 and 2 == 'left'<caret>)) or (3):
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/RedundantParenthesesParenthesizedExpression_after.py b/python/testData/inspections/RedundantParenthesesParenthesizedExpression_after.py
new file mode 100644
index 0000000..0c20127
--- /dev/null
+++ b/python/testData/inspections/RedundantParenthesesParenthesizedExpression_after.py
@@ -0,0 +1,2 @@
+if (1 and 2 == 'left') or (3):
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/ReplacePrint_after.py b/python/testData/inspections/ReplacePrint_after.py
index 22a695b..51bf35e 100644
--- a/python/testData/inspections/ReplacePrint_after.py
+++ b/python/testData/inspections/ReplacePrint_after.py
@@ -1 +1,3 @@
+from __future__ import print_function
+
print("foo")
\ No newline at end of file
diff --git a/python/testData/intentions/beforeTypeAssertionInDictComp.py b/python/testData/intentions/beforeTypeAssertionInDictComp.py
new file mode 100644
index 0000000..79fb9ec
--- /dev/null
+++ b/python/testData/intentions/beforeTypeAssertionInDictComp.py
@@ -0,0 +1 @@
+a = {k: v <caret>for k, v in zip('abc', range(3)) if k % 2}
\ No newline at end of file
diff --git a/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs.py b/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs.py
new file mode 100644
index 0000000..e5a5ec0
--- /dev/null
+++ b/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs.py
@@ -0,0 +1,7 @@
+class A(object):
+ def __init__(self):
+ pass
+
+class B(A):
+ def <warning descr="Call to __init__ of super class is missed">__in<caret>it__</warning>(self, **kwargs):
+ pass
\ No newline at end of file
diff --git a/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs_after.py b/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs_after.py
new file mode 100644
index 0000000..b15ed35
--- /dev/null
+++ b/python/testData/quickFixes/AddCallSuperQuickFixTest/kwargs_after.py
@@ -0,0 +1,7 @@
+class A(object):
+ def __init__(self):
+ pass
+
+class B(A):
+ def __init__(self, **kwargs):
+ super(B, self).__init__()
\ No newline at end of file
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py
index 3663937..330ef0e 100644
--- a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py
@@ -2,7 +2,8 @@
def foo(r<caret>):
"""
- :param r:
+ :param r: some parameter
+ :type r: int
:return:
"""
def a():
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStar.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStar.py
new file mode 100644
index 0000000..5d9d054
--- /dev/null
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStar.py
@@ -0,0 +1,2 @@
+def f1(*, u<caret>p):
+ pass
\ No newline at end of file
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam.py
new file mode 100644
index 0000000..21116ae
--- /dev/null
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam.py
@@ -0,0 +1,8 @@
+def f1(*, u<caret>p, another):
+ """
+ :param up: my param
+ :type up: int
+ :rtype: int
+
+ """
+ print(another)
\ No newline at end of file
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam_after.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam_after.py
new file mode 100644
index 0000000..998a21d
--- /dev/null
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/singleStarTwoParam_after.py
@@ -0,0 +1,6 @@
+def f1(*, another):
+ """
+ :rtype: int
+
+ """
+ print(another)
\ No newline at end of file
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage.py
new file mode 100644
index 0000000..e2706c6
--- /dev/null
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage.py
@@ -0,0 +1,5 @@
+def f1(a, u<caret>p, c):
+ print a
+ print c
+
+f1(1, 2, 3)
\ No newline at end of file
diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage_after.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage_after.py
new file mode 100644
index 0000000..9e59c62
--- /dev/null
+++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/usage_after.py
@@ -0,0 +1,5 @@
+def f1(a, c):
+ print a
+ print c
+
+f1(1, 3)
\ No newline at end of file
diff --git a/python/testData/refactoring/changeSignature/decorator.after.py b/python/testData/refactoring/changeSignature/decorator.after.py
new file mode 100644
index 0000000..83350ab
--- /dev/null
+++ b/python/testData/refactoring/changeSignature/decorator.after.py
@@ -0,0 +1,10 @@
+
+def decorator(arg1):
+ print('Wrapped with', arg1, arg2)
+ def wraps(f):
+ return f
+ return wraps
+
+@decorator('arg1')
+def do_things():
+ print('Things done')
\ No newline at end of file
diff --git a/python/testData/refactoring/changeSignature/decorator.before.py b/python/testData/refactoring/changeSignature/decorator.before.py
new file mode 100644
index 0000000..dfdc89f
--- /dev/null
+++ b/python/testData/refactoring/changeSignature/decorator.before.py
@@ -0,0 +1,10 @@
+
+def dec<caret>orator(arg1, arg2):
+ print('Wrapped with', arg1, arg2)
+ def wraps(f):
+ return f
+ return wraps
+
+@decorator('arg1', 'arg2')
+def do_things():
+ print('Things done')
\ No newline at end of file
diff --git a/python/testData/refactoring/inlinelocal/comment.after.py b/python/testData/refactoring/inlinelocal/comment.after.py
new file mode 100644
index 0000000..2ee8e7c
--- /dev/null
+++ b/python/testData/refactoring/inlinelocal/comment.after.py
@@ -0,0 +1,2 @@
+# some clever comment
+value = "aaaaaa" + "bbbbb"
diff --git a/python/testData/refactoring/inlinelocal/comment.before.py b/python/testData/refactoring/inlinelocal/comment.before.py
new file mode 100644
index 0000000..4fe5976
--- /dev/null
+++ b/python/testData/refactoring/inlinelocal/comment.before.py
@@ -0,0 +1,2 @@
+temp = "aaaaaa" # some clever comment
+value = te<caret>mp + "bbbbb"
diff --git a/python/testData/refactoring/introduceVariable/generatorParameter.after.py b/python/testData/refactoring/introduceVariable/generatorParameter.after.py
new file mode 100644
index 0000000..0070465
--- /dev/null
+++ b/python/testData/refactoring/introduceVariable/generatorParameter.after.py
@@ -0,0 +1,2 @@
+a = (row for row in [123] if row == "beetle")
+any(a)
\ No newline at end of file
diff --git a/python/testData/refactoring/introduceVariable/generatorParameter.py b/python/testData/refactoring/introduceVariable/generatorParameter.py
new file mode 100644
index 0000000..938c22a
--- /dev/null
+++ b/python/testData/refactoring/introduceVariable/generatorParameter.py
@@ -0,0 +1 @@
+any(row <caret>for row in [123] if row == "beetle")
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PyConsoleIndentTest.java b/python/testSrc/com/jetbrains/python/PyConsoleIndentTest.java
index 13a83c0..a017105 100644
--- a/python/testSrc/com/jetbrains/python/PyConsoleIndentTest.java
+++ b/python/testSrc/com/jetbrains/python/PyConsoleIndentTest.java
@@ -55,6 +55,42 @@
doTest(2);
}
+ public void testIndent8() {
+ doTest();
+ }
+
+ public void testIndent9() {
+ doTest();
+ }
+
+ public void testIndent10() {
+ doTest();
+ }
+
+ public void testIndent11() {
+ doTest();
+ }
+
+ public void testIndent12() {
+ doTest();
+ }
+
+ public void testIndent13() {
+ doTest();
+ }
+
+ public void testIndent14() {
+ doTest();
+ }
+
+ public void testIndent15() {
+ doTest();
+ }
+
+ public void testIndent16() {
+ doTest();
+ }
+
private void doTest() {
doTest(0);
}
diff --git a/python/testSrc/com/jetbrains/python/PyEditingTest.java b/python/testSrc/com/jetbrains/python/PyEditingTest.java
index 84470af..2a0310a 100644
--- a/python/testSrc/com/jetbrains/python/PyEditingTest.java
+++ b/python/testSrc/com/jetbrains/python/PyEditingTest.java
@@ -403,6 +403,11 @@
doTestEnter("<caret>''", "\n''");
}
+ public void testEnterInUnicodeString() {
+ doTestEnter("a = u\"some <caret>text\"", "a = u\"some \" \\\n" +
+ " u\"<caret>text\"");
+ }
+
public void testBackslashInParenthesis() { // PY-5106
doTestEnter("(\"some <caret>string\", 1)", "(\"some \"\n" +
" \"string\", 1)");
diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java
index fb45fae..ec7e7ed 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java
@@ -175,9 +175,9 @@
}
public void testPropNewSetter() {
+ PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
Map<String, PsiElement> marks = loadTest();
PsiElement ref_elt = marks.get("<the_ref>");
- PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
try {
final PyDocStringOwner doc_owner = (PyDocStringOwner)((PyTargetExpression)(ref_elt.getParent())).getReference().resolve();
checkByHTML(myProvider.generateDoc(doc_owner, ref_elt));
@@ -188,9 +188,9 @@
}
public void testPropNewDeleter() {
+ PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
Map<String, PsiElement> marks = loadTest();
PsiElement ref_elt = marks.get("<the_ref>");
- PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON26);
try {
final PyDocStringOwner doc_owner = (PyDocStringOwner)((PyReferenceExpression)(ref_elt.getParent())).getReference().resolve();
checkByHTML(myProvider.generateDoc(doc_owner, ref_elt));
diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
index 2f5d1f7..fde0c2e 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
@@ -205,6 +205,11 @@
PyBundle.message("QFIX.redundant.parentheses"), true, true);
}
+ public void testRedundantParenthesesParenthesizedExpression() { // PY-12679
+ doInspectionTest("RedundantParenthesesParenthesizedExpression.py", PyRedundantParenthesesInspection.class,
+ PyBundle.message("QFIX.redundant.parentheses"), true, true);
+ }
+
public void testChainedComparisons() { // PY-1020
doInspectionTest("ChainedComparisons.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java
index e04f064..0904b4c 100644
--- a/python/testSrc/com/jetbrains/python/PyStubsTest.java
+++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java
@@ -58,12 +58,12 @@
}
public void testStubStructure() {
- final PyFile file = getTestFile();
// vfile is problematic, but we need an SDK to check builtins
- final Project project = file.getProject();
+ final Project project = myFixture.getProject();
+ PythonLanguageLevelPusher.setForcedLanguageLevel(project, LanguageLevel.PYTHON26); // we need 2.6+ for @foo.setter
try {
- PythonLanguageLevelPusher.setForcedLanguageLevel(project, LanguageLevel.PYTHON26); // we need 2.6+ for @foo.setter
+ final PyFile file = getTestFile();
final List<PyClass> classes = file.getTopLevelClasses();
assertEquals(3, classes.size());
PyClass pyClass = classes.get(0);
diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
index 77246ba..e1fa67d 100644
--- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
@@ -110,6 +110,15 @@
public void testYieldOutsideOfFunction() {
doTest(LanguageLevel.PYTHON27, true, true);
}
+
+ public void testYieldInDefaultValue() {
+ doTest(LanguageLevel.PYTHON34, true, false);
+ }
+
+ // PY-11663
+ public void testYieldInLambda() {
+ doTest();
+ }
public void testImportStarAtTopLevel() {
doTest(true, false);
diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java
index cf357f9..2891d81 100644
--- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java
+++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java
@@ -353,6 +353,10 @@
doTestTypeAssertion();
}
+ public void testTypeAssertionInDictComp() { //PY-7971
+ doNegativeTest(PyBundle.message("INTN.insert.assertion"));
+ }
+
private void doTestTypeAssertion() {
doTest(PyBundle.message("INTN.insert.assertion"));
}
diff --git a/python/testSrc/com/jetbrains/python/quickFixes/AddCallSuperQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/AddCallSuperQuickFixTest.java
index 6ff97dc..a816abc 100644
--- a/python/testSrc/com/jetbrains/python/quickFixes/AddCallSuperQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/quickFixes/AddCallSuperQuickFixTest.java
@@ -30,4 +30,8 @@
public void testNewStyle() {
doQuickFixTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"));
}
+
+ public void testKwargs() {
+ doQuickFixTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"));
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java
index 32fc35d..b162a1e 100644
--- a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java
@@ -15,10 +15,13 @@
*/
package com.jetbrains.python.quickFixes;
+import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.testFramework.TestDataPath;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyQuickFixTestCase;
import com.jetbrains.python.inspections.PyUnusedLocalInspection;
+import com.jetbrains.python.psi.LanguageLevel;
+import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
@TestDataPath("$CONTENT_ROOT/../testData//quickFixes/PyRemoveParameterQuickFixTest/")
public class PyRemoveParameterQuickFixTest extends PyQuickFixTestCase {
@@ -34,4 +37,28 @@
public void testDocstring() {
doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter"));
}
+
+ public void testUsage() {
+ doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter"));
+ }
+
+ public void testSingleStarTwoParam() {
+ doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter"), LanguageLevel.PYTHON33);
+ }
+
+ public void testSingleStar() {
+ PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON33);
+ try {
+ final String testFileName = getTestName(true);
+ myFixture.enableInspections(PyUnusedLocalInspection.class);
+ myFixture.configureByFile(testFileName + ".py");
+ myFixture.checkHighlighting(true, false, false);
+ final IntentionAction intentionAction = myFixture.getAvailableIntention(PyBundle.message("QFIX.NAME.remove.parameter"));
+ assertNull(intentionAction);
+ }
+ finally {
+ PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
+ }
+
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
index e31c25a..4f02da1 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
@@ -80,4 +80,8 @@
public void testPy5832() {
doTest();
}
+
+ public void testComment() {
+ doTest();
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
index 5899104..f211797 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyIntroduceVariableTest.java
@@ -224,6 +224,10 @@
doTest();
}
+ public void testGeneratorParameter() {
+ doTest();
+ }
+
// PY-10964
public void testMultiReference() {
myFixture.configureByFile(getTestName(true) + ".py");
diff --git a/python/testSrc/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureTest.java b/python/testSrc/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureTest.java
index a9984f6..fd7bb1e 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureTest.java
@@ -31,7 +31,7 @@
/**
* User : ktisha
*/
-@TestDataPath("$CONTENT_ROOT/../testData/refactoring/changeSignature/")
+@TestDataPath("$CONTENT_ROOT/../testData/")
public class PyChangeSignatureTest extends PyTestCase {
public void testChooseSuperMethod() {
@@ -176,6 +176,10 @@
PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name"));
}
+ public void testDecorator() {
+ doChangeSignatureTest("decorator", Arrays.asList(new PyParameterInfo(0, "arg1", null, false)));
+ }
+
public void testNonDefaultAfterDefault() {
doValidationTest(null, Arrays.asList(new PyParameterInfo(-1, "a", "2", false), new PyParameterInfo(1, "b", "2", false)), null);
}