master c771e9a39170 cached
403 files
3.2 MB
855.6k tokens
1979 symbols
1 requests
Download .txt
Showing preview only (3,422K chars total). Download the full file or copy to clipboard to get everything.
Repository: pythonanywhere/dirigible-spreadsheet
Branch: master
Commit: c771e9a39170
Files: 403
Total size: 3.2 MB

Directory structure:
gitextract_vy1u92c1/

├── .gitignore
├── LICENSE.md
├── README.md
├── dirigible/
│   ├── .gitignore
│   ├── dirigible/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── test_utils.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── featured_sheet/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── featured_sheets.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_models.py
│   │   └── views.py
│   ├── feedback/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── fts/
│   │   ├── __init__.py
│   │   ├── screendumps/
│   │   │   └── placeholder
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── functionaltest.py
│   │       ├── test_2521_CodeEditor.py
│   │       ├── test_2525_LoginLogout.py
│   │       ├── test_2528_CreateEditSheet.py
│   │       ├── test_2529_HighlightErrorsInCells.py
│   │       ├── test_2531_DifficultStuffInCells.py
│   │       ├── test_2532_LambdasInCells.py
│   │       ├── test_2533_Numpy.py
│   │       ├── test_2534_JsonWorksheets.py
│   │       ├── test_2535_RunWorksheetSerial.py
│   │       ├── test_2536_ParallelFormulaExecution.py
│   │       ├── test_2537_ErrorsInConsole.py
│   │       ├── test_2538_ShowStdoutInConsole.py
│   │       ├── test_2540_FrontPage.py
│   │       ├── test_2544_403_404_and_500_pages.py
│   │       ├── test_2545_PageResizeBehaviour.py
│   │       ├── test_2546_ListSheetsOnDashboard.py
│   │       ├── test_2547_EnterDataQuickly.py
│   │       ├── test_2548_UserCode.py
│   │       ├── test_2549_InterruptedRecalculations.py
│   │       ├── test_2550_EditableSheetName.py
│   │       ├── test_2554_SlicingInFormulae.py
│   │       ├── test_2556_BrokenUserCode.py
│   │       ├── test_2557_ClickAwaySavesUsercode.py
│   │       ├── test_2558_MoreCellsByDefault.py
│   │       ├── test_2559_FitEditorToCells.py
│   │       ├── test_2562_ErrorInCellShouldBeClearedByConstants.py
│   │       ├── test_2565_JSONAPIAuth.py
│   │       ├── test_2571_DocumentationAndBlogLinks.py
│   │       ├── test_2577_SaveColumnWidths.py
│   │       ├── test_2581_FormulaBar.py
│   │       ├── test_2582_ReferencingEmptyCell.py
│   │       ├── test_2592_Cut_Copy_Paste_Within_Dirigible.py
│   │       ├── test_2595_Spinner.py
│   │       ├── test_2597_CapRecalcTime.py
│   │       ├── test_2601_UndefinedShouldBeAvailableToUsercode.py
│   │       ├── test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete.py
│   │       ├── test_2603_WorksheetsMayOnlyContainCells.py
│   │       ├── test_2616_RootPageIsDashboard.py
│   │       ├── test_2621_CanSaveSheetsWithLotsOfFormulae.py
│   │       ├── test_2622_CellRanges.py
│   │       ├── test_2631_BlogRedirect.py
│   │       ├── test_2633_CursorKeysMoveAroundGrid.py
│   │       ├── test_2635_SheetNameSelectedOnEdit.py
│   │       ├── test_2639_SciPy_and_MpMath.py
│   │       ├── test_2642_RecalcTimesInConsole.py
│   │       ├── test_2644_AdminOmniscience.py
│   │       ├── test_2650_UsercodeSandbox.py
│   │       ├── test_2651_SaveSheetNameOnBlur.py
│   │       ├── test_2652_CommitCellOnBlur.py
│   │       ├── test_2653_UsernameFocusedOnLoginPage.py
│   │       ├── test_2654_CtrlSSavesUsercode.py
│   │       ├── test_2678_GlobalStateNotShared.py
│   │       ├── test_2682_CellAccessUsingA1.py
│   │       ├── test_2685_ChangePassword.py
│   │       ├── test_2689_DontClearCellEditorWhenRecalcsHitClient.py
│   │       ├── test_2690_FocusShouldStartInGrid.py
│   │       ├── test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants.py
│   │       ├── test_2701_NameResolutionWorks.py
│   │       ├── test_2702_HttpsInChrootJail.py
│   │       ├── test_2704_OldStyleClassesInTheGrid.py
│   │       ├── test_2711_ImportExcel.py
│   │       ├── test_2712_ImportCSV.py
│   │       ├── test_2726_FormulaBarTextSelection.py
│   │       ├── test_2734_ClearCells.py
│   │       ├── test_2735_CtrlKeysArePassedOnToBrowser.py
│   │       ├── test_2741_Xlrd.py
│   │       ├── test_2749_DisallowArbitraryKeysForWorksheet.py
│   │       ├── test_2751_UsefulModules.py
│   │       ├── test_2758_LoadGridDataOnDemand.py
│   │       ├── test_2762_PythonConversion.py
│   │       ├── test_2770_ClearDependentCellErrors.py
│   │       ├── test_2774_ExportCSV.py
│   │       ├── test_2781_FormulaAndFormattedValueMustBeStrings.py
│   │       ├── test_2787_SignUp.py
│   │       ├── test_2789_ErrorConsoleHTMLEscape.py
│   │       ├── test_2795_Rewrite_Formulae_during_Cut_and_Paste.py
│   │       ├── test_2799_FillDownDuringPaste.py
│   │       ├── test_2812_CutCopyPasteInEditMode.py
│   │       ├── test_2814_PublicWorksheets.py
│   │       ├── test_2828_GridShouldNotStealFocusOnRecalc.py
│   │       ├── test_2839_CutCopyPasteButtons.py
│   │       ├── test_2844_CantMakeRowHeaderActive.py
│   │       ├── test_2848_WorksheetBounds.py
│   │       ├── test_2862_CopyAndPasteFormulaWithErrors.py
│   │       ├── test_2872_CellTooltips.py
│   │       ├── test_2873_IE_Warning.py
│   │       ├── test_2884_FeedbackForm.py
│   │       └── test_data/
│   │           ├── T2711-badly-named-png.xls
│   │           ├── T2711-import-excel.xls
│   │           ├── csv_file.csv
│   │           ├── excel_generated_csv.csv
│   │           ├── expected_csv_file.csv
│   │           ├── expected_unicode_csv.csv
│   │           ├── japanese.csv
│   │           └── public_sheet_csv_file.csv
│   ├── info_pages/
│   │   ├── __init__.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   ├── non_logged_in_front_page.html
│   │   │   ├── oss.html
│   │   │   └── video.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   └── views.py
│   ├── manage.py
│   ├── registration/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── forms.py
│   │   ├── locale/
│   │   │   ├── ar/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── bg/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── de/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── el/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── en/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── es/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── es_AR/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── fr/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── he/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── it/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── ja/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── nl/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── pl/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── pt_BR/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── ru/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── sr/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── sv/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── zh_CN/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   └── zh_TW/
│   │   │       └── LC_MESSAGES/
│   │   │           ├── django.mo
│   │   │           └── django.po
│   │   ├── management/
│   │   │   ├── __init__.py
│   │   │   └── commands/
│   │   │       ├── __init__.py
│   │   │       └── cleanupregistration.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── shared/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── static/
│   │   │   ├── ace/
│   │   │   │   ├── ace-uncompressed.js
│   │   │   │   ├── ace.js
│   │   │   │   ├── cockpit-uncompressed.js
│   │   │   │   ├── cockpit.js
│   │   │   │   ├── mode-python.js
│   │   │   │   └── worker-javascript.js
│   │   │   ├── dirigible/
│   │   │   │   ├── examples/
│   │   │   │   │   └── pricelist-json-api-demo.html
│   │   │   │   ├── images/
│   │   │   │   │   └── toolbar/
│   │   │   │   │       └── api_button_disabled.pdn
│   │   │   │   ├── scripts/
│   │   │   │   │   ├── cell_editor.js
│   │   │   │   │   ├── console_view.js
│   │   │   │   │   ├── dialogs.js
│   │   │   │   │   ├── editor_commands.js
│   │   │   │   │   ├── feedback_dialog.js
│   │   │   │   │   ├── grid_commands.js
│   │   │   │   │   ├── grid_content_converter.js
│   │   │   │   │   ├── grid_interaction_handler.js
│   │   │   │   │   ├── grid_remote_model.js
│   │   │   │   │   ├── grid_view.js
│   │   │   │   │   ├── htmlescape.js
│   │   │   │   │   ├── keyboard_cellrange_selector.js
│   │   │   │   │   ├── page_commands.js
│   │   │   │   │   ├── page_interaction_handler.js
│   │   │   │   │   ├── page_view.js
│   │   │   │   │   ├── security_settings.js
│   │   │   │   │   ├── selection_model.js
│   │   │   │   │   ├── sheet_page_utils.js
│   │   │   │   │   ├── toolbar_interaction_handler.js
│   │   │   │   │   └── usercode_view.js
│   │   │   │   ├── styles/
│   │   │   │   │   ├── base.css
│   │   │   │   │   ├── coming_soon_page.css
│   │   │   │   │   ├── contact.css
│   │   │   │   │   ├── error.css
│   │   │   │   │   ├── index.css
│   │   │   │   │   ├── info_page.css
│   │   │   │   │   ├── login.css
│   │   │   │   │   ├── non_sheet_page.css
│   │   │   │   │   ├── pricing.css
│   │   │   │   │   ├── registration.css
│   │   │   │   │   ├── sheet_page.css
│   │   │   │   │   ├── user_page.css
│   │   │   │   │   └── video.css
│   │   │   │   └── tests/
│   │   │   │       ├── cell_editor_test.html
│   │   │   │       ├── console_view_test.html
│   │   │   │       ├── dialogs_test.html
│   │   │   │       ├── editor_commands_test.html
│   │   │   │       ├── feedback_dialog_test.html
│   │   │   │       ├── grid_commands_test.html
│   │   │   │       ├── grid_content_converter_test.html
│   │   │   │       ├── grid_interaction_handler_test.html
│   │   │   │       ├── grid_remote_model_test.html
│   │   │   │       ├── grid_view_test.html
│   │   │   │       ├── htmlescape_test.html
│   │   │   │       ├── jsmock.js
│   │   │   │       ├── logger.css
│   │   │   │       ├── page_commands_test.html
│   │   │   │       ├── page_interaction_handler_test.html
│   │   │   │       ├── page_view_test.html
│   │   │   │       ├── security_settings_test.html
│   │   │   │       ├── selection_model_test.html
│   │   │   │       ├── sheet_page_utils_test.html
│   │   │   │       ├── test_utils.js
│   │   │   │       ├── test_utils_test.html
│   │   │   │       ├── testlogger.css
│   │   │   │       ├── toolbar_interaction_handler_test.html
│   │   │   │       ├── usercode_view_test.html
│   │   │   │       ├── yuirunner.js
│   │   │   │       └── yuitest/
│   │   │   │           └── yuitest-combo.js
│   │   │   ├── jquery/
│   │   │   │   ├── jeip.js
│   │   │   │   ├── jquery-ui-1.8.10.custom.css
│   │   │   │   ├── jquery.ajaxq-0.0.1.js
│   │   │   │   └── jquery.cookie.js
│   │   │   ├── json/
│   │   │   │   └── json2.js
│   │   │   ├── robots.txt
│   │   │   ├── slickgrid/
│   │   │   │   ├── MIT-LICENSE.txt
│   │   │   │   ├── slick.cellrangedecorator.js
│   │   │   │   ├── slick.cellrangeselector.js
│   │   │   │   ├── slick.cellselectionmodel.js
│   │   │   │   ├── slick.core.js
│   │   │   │   ├── slick.editors.js
│   │   │   │   ├── slick.grid.css
│   │   │   │   └── slick.grid.js
│   │   │   └── splitter/
│   │   │       └── splitter.js
│   │   ├── templates/
│   │   │   ├── 403.html
│   │   │   ├── 404.html
│   │   │   ├── 500.html
│   │   │   ├── base.html
│   │   │   ├── error_page.html
│   │   │   ├── footer_links_include.html
│   │   │   ├── header_links_include.html
│   │   │   ├── info_page.html
│   │   │   └── non_sheet_page_small_logo.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   └── views.py
│   ├── sheet/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── calculate.py
│   │   ├── cell.py
│   │   ├── cell_range.py
│   │   ├── clipboard.py
│   │   ├── dependency_graph.py
│   │   ├── dirigible_datetime.py
│   │   ├── errors.py
│   │   ├── eval_constant.py
│   │   ├── forms.py
│   │   ├── formula_interpreter.py
│   │   ├── importer.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── parser/
│   │   │   ├── __init__.py
│   │   │   ├── fl_cell_range_parse_node.py
│   │   │   ├── fl_cell_reference_parse_node.py
│   │   │   ├── fl_column_reference_parse_node.py
│   │   │   ├── fl_named_column_reference_parse_node.py
│   │   │   ├── fl_named_row_reference_parse_node.py
│   │   │   ├── fl_reference_parse_node.py
│   │   │   ├── fl_row_reference_parse_node.py
│   │   │   ├── grammar.py
│   │   │   ├── parse_node.py
│   │   │   ├── parse_node_constructors.py
│   │   │   ├── parser.py
│   │   │   ├── parsetab.py
│   │   │   └── tokens.py
│   │   ├── rewrite_formula_offset_cell_references.py
│   │   ├── sheet.py
│   │   ├── templates/
│   │   │   ├── export_csv_error.html
│   │   │   ├── import_csv_error.html
│   │   │   ├── import_xls_error.html
│   │   │   └── sheet_page.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── parser/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_fl_cell_range_parse_node.py
│   │   │   │   ├── test_fl_cell_reference_parse_node.py
│   │   │   │   ├── test_fl_coloumn_reference_parse_node.py
│   │   │   │   ├── test_fl_named_column_reference_parse_node.py
│   │   │   │   ├── test_fl_named_row_reference_parse_node.py
│   │   │   │   ├── test_fl_reference_parse_node.py
│   │   │   │   ├── test_fl_row_reference_parse_node.py
│   │   │   │   ├── test_parse_node.py
│   │   │   │   ├── test_parse_node_constructors.py
│   │   │   │   └── test_parser.py
│   │   │   ├── test_calculate.py
│   │   │   ├── test_cell.py
│   │   │   ├── test_cell_range.py
│   │   │   ├── test_clipboard.py
│   │   │   ├── test_dependency_graph.py
│   │   │   ├── test_dirigible_datetime.py
│   │   │   ├── test_errors.py
│   │   │   ├── test_eval_constant.py
│   │   │   ├── test_forms.py
│   │   │   ├── test_formula_interpreter.py
│   │   │   ├── test_importer.py
│   │   │   ├── test_rewrite_formula_offset_cell_references.py
│   │   │   ├── test_sheet.py
│   │   │   ├── test_ui_jsonifier.py
│   │   │   ├── test_views.py
│   │   │   ├── test_views_api_0_1.py
│   │   │   ├── test_worksheet.py
│   │   │   └── utils/
│   │   │       ├── __init__.py
│   │   │       ├── test_cell_name_utils.py
│   │   │       ├── test_interruptable_thread.py
│   │   │       └── test_string_utils.py
│   │   ├── ui_jsonifier.py
│   │   ├── urls.py
│   │   ├── urls_api_0_1.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── cell_name_utils.py
│   │   │   ├── interruptable_thread.py
│   │   │   └── string_utils.py
│   │   ├── views.py
│   │   ├── views_api_0_1.py
│   │   └── worksheet.py
│   └── user/
│       ├── __init__.py
│       ├── admin.py
│       ├── forms.py
│       ├── migrations/
│       │   ├── 0001_initial.py
│       │   └── __init__.py
│       ├── models.py
│       ├── signup_urls.py
│       ├── templates/
│       │   ├── login.html
│       │   ├── registration/
│       │   │   ├── activate.html
│       │   │   ├── activation_email.txt
│       │   │   ├── activation_email_subject.txt
│       │   │   ├── registration_complete.html
│       │   │   └── registration_form.html
│       │   ├── user_page.html
│       │   └── welcome_email.txt
│       ├── tests/
│       │   ├── __init__.py
│       │   ├── test_forms.py
│       │   ├── test_models.py
│       │   └── test_views.py
│       ├── urls.py
│       └── views.py
├── documentation/
│   ├── .gitignore
│   ├── BeautifulSoup.py
│   ├── Makefile
│   ├── _static/
│   │   └── file-to-force-git-to-keep-empty-dir
│   ├── _templates/
│   │   └── layout.html
│   ├── builtins.rst
│   ├── conf.py
│   ├── dirigible-theme/
│   │   ├── layout.html
│   │   ├── static/
│   │   │   └── dirigible-style.css
│   │   └── theme.conf
│   ├── fl-python-differences.rst
│   ├── import_export.rst
│   ├── index.rst
│   ├── json_api.rst
│   ├── overview.rst
│   ├── public_sheets.rst
│   ├── python-modules.rst
│   ├── spreadsheet-functions.rsl
│   ├── spreadsheet-functions.rst
│   ├── talk.md
│   ├── talk_example_sheets.json
│   ├── tutorial01.rst
│   ├── tutorial02.rst
│   ├── tutorial03.rst
│   └── tutorial04.rst
└── requirements.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.pyc
python/dirigible/dirigible.db


================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)

Copyright (c) 2014 Resolver Systems Ltd, PythonAnywhere LLP

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.



================================================
FILE: README.md
================================================
Dirigible, the web-based Pythonic Spreadsheet
=============================================

This is the source code from the end-of-lifed https://www.projectdirigible.com project, preserved for posterity and the curious


Installation instructions
-------------------------

    cd dirigible
    pip install -r requirements.txt
    python manage.py migrate
    python manage.py createsuperuser  # make yourself a user account.
    python manage.py runserver

And visit http://localhost:8000

Security
--------

This version of Dirigible has absolutely no security, so bewarned, before you put this on a public server -- anyone that logs in has the full access permissions of whichever user is running django, and you can use Python to do pretty much whatever you want!

Check out the chroot_recalculation branch for a slightly more secure approach


Some minimal context
--------------------

(Probably best to play around with the spreadsheet a bit before reading this guide, to get an idea of what is possible.  Try creating a couple of formulae with calculations, and maybe using a user-defined function from the usercode panel)

* A Dirigible spreadsheet is "just" a python program, which is visible in the usercode panel on the right.  

* Recalculating the spreadsheet means executing that code, including two very important built-in functions:  `load_constants` and `evaluate_formulae`.  

In between those two functions, the user can add their own arbitrary code. 

One global object is accessible, the `worksheet` ([source](https://github.com/pythonanywhere/dirigible-spreadsheet/blob/master/dirigible/sheet/worksheet.py))

A worksheet is compose of cells (it is in fact a dictionary, whose keys are the location, expressed as a tuple of column,row, and whose values are cell objects)

A cell ([source](https://github.com/pythonanywhere/dirigible-spreadsheet/blob/master/dirigible/sheet/cell.py)) has two key attributes:

- its `formula`, which may just be a constant like "hello" or "12,3", or a formula, like =A1+B1
- its `value`, which is the result of evaluating the formula.  

If the formula is a constant, its value is that constant.

If it's a real formula, then it will be evaluated as part of `evaluate_formulae()`.  This involves:

1. Parsing the formula ([source](https://github.com/pythonanywhere/dirigible-spreadsheet/blob/master/dirigible/sheet/formula_interpreter.py))
    - cell formulae can include any valid python, as well as
    - special spreadsheet syntax, including cell references like A1 or B2, and special spreadsheet formulae like the SUM function
    - any special spreadsheet syntax is parsed and converted to Python
    - and finding out the `dependencies`.  If the formula for cell A1 includes a reference to B1, then B1 is a dependency of A1

2. Placing it into the whole spreadsheet's dependency graph ([source](https://github.com/pythonanywhere/dirigible-spreadsheet/blob/master/dirigible/sheet/dependency_graph.py))

3. Evaluating all the branches of that graph, starting from its leaves, by evaluating the cell's formula to get its value.  That can then be fed into cells that depend on it, and so on.  (See [calculate.py](https://github.com/pythonanywhere/dirigible-spreadsheet/blob/master/dirigible/sheet/calculate.py))

Cell formulae can also use any user-defined functions from the usercode.


Everything else is fairly peripheral.  There is some monkeying around with json, some stuff with threads that's a throwback to some parallelisation features that I haven't finished removing.

Questions and requests for clarification are solicited, as are any pull requests for documentation, bugfixes, fixes to unit tests (of which all but three were passing in this modified version of our codebase, at the time of writing), or FTs (half-ported from old selenium)



================================================
FILE: dirigible/.gitignore
================================================
db.sqlite3
fts/screendumps


================================================
FILE: dirigible/dirigible/__init__.py
================================================


================================================
FILE: dirigible/dirigible/settings.py
================================================
"""
Django settings for dirigible project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0590fte(p#@fk+ii_-vfzwuixst9z)nqzszr!wx7pkjv++sa%2'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'registration',
    'user',
    'feedback',
    'info_pages',
    'featured_sheet',
    'sheet',
    'shared',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'dirigible.urls'

WSGI_APPLICATION = 'dirigible.wsgi.application'


# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = False


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/

STATIC_URL = '/static/'

LOGIN_URL = '/login'
LOGIN_REDIRECT_URL = '/'

FEEDBACK_EMAIL = 'support@example.com'


================================================
FILE: dirigible/dirigible/test_utils.py
================================================
# Copyright (c) 2005-2010 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

try:
    import unittest2 as unittest
except ImportError:
    import unittest

from os.path import dirname, join
import sys

import django


def create_suite_for_file_directory(file):
    def suite():
        start_dir = dirname(file)
        return unittest.defaultTestLoader.discover(
            start_dir,
            top_level_dir=join(dirname(__file__), "..")
        )
    return suite


def die(exception=None):
    if exception is None:
        exception = AssertionError('die called')
    def inner_die(*_):
        raise exception
    return inner_die



class ResolverTestMixins(object):
    def assertCalledOnce(self, mock, *args, **kwargs):
        if mock.call_args_list == []:
            self.fail('Not called')
        self.assertEquals(mock.call_args_list, [(args, kwargs)])



class ResolverTestCase(unittest.TestCase, ResolverTestMixins):
    maxDiff = None



class ResolverDjangoTestCase(django.test.TestCase, ResolverTestMixins):
    maxDiff = None



TEST_CLASSES = (
    unittest.TestCase,
    django.test.TestCase,
    django.test.TransactionTestCase,
    ResolverTestCase,
    ResolverDjangoTestCase
)

def assert_security_classes_exist(test, module_name, excludes=None):
    '''
    ensure that, as a minimum sanity check, each non-security test class in
    this module has an associated security test class.
    '''
    test_classes = [
        name for name, item in sys.modules[module_name].__dict__.iteritems()
        if isinstance(item, type) and issubclass(item, TEST_CLASSES)
        and not item in TEST_CLASSES
    ]
    regular_test_classes = [
        name for name in test_classes
        if not name.endswith('SecurityTest')
    ]
    if excludes is None:
        excludes = []
    for name in regular_test_classes:
        if name not in excludes:
            test.assertTrue(
                name[:-4] + 'SecurityTest' in test_classes,
                "class %s doesn't have a security test. "
                "Use user page security test as template" % (name,)
            )



================================================
FILE: dirigible/dirigible/urls.py
================================================
import os

from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from django.views.generic import TemplateView

from info_pages.views import front_page_view, info_page_view
from sheet.views import new_sheet


urlpatterns = patterns(
    '',

    url(
        r'^$',
        front_page_view,
        name='front_page'
    ),

    url(
        r'^(?P<template_name>oss|video)/',
        info_page_view,
        name="info_page"
    ),

    url(
        # If you change this, don't forget to change the LOGIN_URL in settings.py
        # Here be dragons. The settings .py one has no trailing slash and needs to
        # stay that way. Changing either of these will stop it from working in Chrome
        # and in Firefox if you press ENTER to login.
        r'^login/',
        'django.contrib.auth.views.login',
        {'template_name': 'login.html'},
        name="login"
    ),

    url(
        r'^logout$',
        'django.contrib.auth.views.logout',
        {'next_page': settings.LOGIN_URL},
        name="logout"
    ),

    url(
        r'^new_sheet$',
        new_sheet,
        name="new_sheet"
    ),

    url(
        r'^user/',
        include('user.urls')
    ),

    url(
        r'^signup/',
        include('user.signup_urls')
    ),


    url(
        r'^feedback/',
        include('feedback.urls')
    ),


    url(
        r'^featured_sheets/$',
        TemplateView.as_view(template_name='featured_sheets.html'),#, context={'sheets': FeaturedSheet.objects.all}),
        name='featured_sheets'
    ),

    url(r'^admin/', include(admin.site.urls)),

)


================================================
FILE: dirigible/dirigible/wsgi.py
================================================
"""
WSGI config for dirigible project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/
"""

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dirigible.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()


================================================
FILE: dirigible/featured_sheet/__init__.py
================================================


================================================
FILE: dirigible/featured_sheet/admin.py
================================================
# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#
from featured_sheet.models import FeaturedSheet
from django.contrib import admin

admin.site.register(FeaturedSheet)



================================================
FILE: dirigible/featured_sheet/models.py
================================================
# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

from django.db import models

from sheet.models import Sheet

class FeaturedSheet(models.Model):
    sheet = models.ForeignKey(Sheet)
    description = models.TextField()
    more_info_url = models.CharField(max_length=1024, default='', blank=True)

    def __unicode__(self):
        return 'Feature: %s' % (self.sheet.name,)


================================================
FILE: dirigible/featured_sheet/templates/featured_sheets.html
================================================
{% extends "info_page.html" %}

{% block title %}
    Featured Sheets: Dirigible
{% endblock %}

{% block head %}
    {{ block.super }}
    <link rel="stylesheet" href="/static/dirigible/styles/info_page.css" type="text/css" media="screen" charset="utf-8" />
{% endblock %}

{% block middle %}

  <h1>Featured sheets</h1>

    {% for sheet in sheets %}
      <div class="{{sheet.sheet.id}}">
      <div class="featured_sheet_actions">
          {% if sheet.more_info_url %}
          <span class="featured_sheet_more_info">
              <a href="{{sheet.more_info_url}}">More info</a>
          </span>
          {% endif %}
          <span class="featured_sheet_view_link">
              <a  href="{% url sheet_page sheet.sheet.owner.username sheet.sheet.id %}">View sheet</a>
          </span>
          <span class="featured_sheet_copy_link">
              <a  href="{% url sheet_copy_sheet sheet.sheet.owner.username sheet.sheet.id %}">Get a copy</a>
          </span>
      </div>
      <h2 class="featured_sheet_name">
          <a href="{% url sheet_page sheet.sheet.owner.username sheet.sheet.id %}">{{sheet.sheet.name}}</a>
      </h2>
      <div class="featured_sheet_description">{{sheet.description}}</div>
      </div>

        {% endfor %}

{% endblock %}


================================================
FILE: dirigible/featured_sheet/tests/__init__.py
================================================



================================================
FILE: dirigible/featured_sheet/tests/test_models.py
================================================
# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#
from django.contrib.auth.models import User

from dirigible.test_utils import ResolverTestCase
from sheet.models import Sheet

from featured_sheet.models import FeaturedSheet


class TestFeaturedSheetModel(ResolverTestCase):

    def test_can_construct_without_more_info_url(self):
        user = User(username='featurer')
        user.save()
        sheet = Sheet(owner=user, name='sheet to feature')
        sheet.save()

        description = 'twas brillig and the slithy toves'
        fs = FeaturedSheet(sheet=sheet, description=description)
        fs.save()

        self.assertEquals(fs.sheet, sheet)
        self.assertEquals(fs.description, description)
        self.assertEquals(fs.more_info_url, '')


    def test_can_construct_with_more_info_url(self):
        user = User(username='chattyfeaturer')
        user.save()
        sheet = Sheet(owner=user, name='sheet to feature')
        sheet.save()

        description = 'twas brillig and the slithy toves'
        more_info_url = 'http://far.away/'
        fs = FeaturedSheet(sheet=sheet, description=description, more_info_url=more_info_url)
        fs.save()

        self.assertEquals(fs.sheet, sheet)
        self.assertEquals(fs.description, description)
        self.assertEquals(fs.more_info_url, more_info_url)


    def test_unicode(self):
        user = User(username='printyfeaturer')
        user.save()
        sheet = Sheet(owner=user, name='sheet to feature')
        sheet.save()

        description = 'twas brillig and the slithy toves'
        more_info_url = 'http://far.away/'
        fs = FeaturedSheet(sheet=sheet, description=description, more_info_url=more_info_url)
        fs.save()

        self.assertEquals(unicode(fs), u'Feature: %s' % (sheet.name,))



================================================
FILE: dirigible/featured_sheet/views.py
================================================
# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#



================================================
FILE: dirigible/feedback/__init__.py
================================================


================================================
FILE: dirigible/feedback/models.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

from django.db import models


================================================
FILE: dirigible/feedback/tests/__init__.py
================================================



================================================
FILE: dirigible/feedback/tests/test_views.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

from mock import patch
from textwrap import dedent

from django.conf import settings
from django.http import HttpRequest, HttpResponse

from dirigible.test_utils import ResolverTestCase

from feedback.views import submit


class SubmitTest(ResolverTestCase):

    @patch('feedback.views.send_mail')
    def test_submit_with_message_and_email_address_and_username_sends_admin_email_with_all_three(self, mock_send_mail):
        request = HttpRequest()
        request.POST["message"] = "a test message"
        request.POST["email_address"] = "a test email address"
        request.POST["username"] = "a test username"
        request.META['HTTP_REFERER'] = 'a test page'

        response = submit(request)

        self.assertTrue(isinstance(response, HttpResponse))
        self.assertEquals(response.content, "OK")

        self.assertCalledOnce(
            mock_send_mail,
            "User feedback from Dirigible",
            dedent("""
                Username: a test username
                Email address: a test email address
                Page: a test page

                Message:
                a test message
            """),
            settings.SERVER_EMAIL,
            [settings.FEEDBACK_EMAIL]
        )


================================================
FILE: dirigible/feedback/urls.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

from django.conf.urls import *

from feedback.views import submit


urlpatterns = patterns('',

    url(
        r'^submit/$',
        submit,
        name="feedback_submit"
    ),

)


================================================
FILE: dirigible/feedback/views.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP
# See LICENSE.md
#

from textwrap import dedent

from django.core.mail import send_mail
from django.http import HttpResponse
from django.conf import settings



def submit(request):
    send_mail(
        "User feedback from Dirigible",
        dedent("""
            Username: %s
            Email address: %s
            Page: %s

            Message:
            %s
        """) % (
            request.POST["username"], request.POST["email_address"],
            request.META['HTTP_REFERER'], request.POST["message"]
        ),
        settings.SERVER_EMAIL,
        [settings.FEEDBACK_EMAIL]
    )
    return HttpResponse("OK")


================================================
FILE: dirigible/fts/__init__.py
================================================


================================================
FILE: dirigible/fts/screendumps/placeholder
================================================


================================================
FILE: dirigible/fts/tests/__init__.py
================================================


================================================
FILE: dirigible/fts/tests/functionaltest.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#
from __future__ import print_function

from contextlib import contextmanager
from email.parser import Parser
from functools import wraps
from textwrap import dedent
from threading import Thread
from urlparse import urljoin, urlparse, urlunparse
import datetime
import hashlib
import os
import re
import time
import urllib
import urllib2

from django.conf import settings
from django.contrib.auth import BACKEND_SESSION_KEY, SESSION_KEY, HASH_SESSION_KEY
from django.contrib.auth.models import User
from django.contrib.sessions.backends.db import SessionStore
from django.contrib.staticfiles.testing import StaticLiveServerTestCase

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

from sheet.sheet import Sheet

USER_PASSWORD = 'p4ssw0rd'

DEFAULT_WAIT_FOR_TIMEOUT = 2
DEFAULT_TYPING_WAIT = 0.1

CURRENT_API_VERSION = '0.1'
SCREEN_DUMP_LOCATION = os.path.abspath(
    os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'screendumps')
)
IMAP_HOST = ""
IMAP_USERNAME = ""
IMAP_PASSWORD = ""


def _debug(text):
    msg = '{}   {}'.format(round(time.time(), 2), text)
    print(msg)
    # print(msg, file=sys.stderr)


class Url(object):
    ROOT = 'http://localhost:8081/'
    LOGIN = urljoin(ROOT, '/login/')
    LOGOUT = urljoin(ROOT, '/logout')
    NEW_SHEET = urljoin(ROOT, '/new_sheet')
    SIGNUP = urljoin(ROOT, '/signup/register/')
    DOCUMENTATION = urljoin(ROOT, '/documentation/')
    API_DOCS = urljoin(DOCUMENTATION, 'builtins.html')


    @classmethod
    def user_page(cls, username):
        return urljoin(Url.ROOT, '/user/%s/' % (username,))

    @classmethod
    def sheet_page(cls, username, sheet_id):
        return urljoin(cls.user_page(username), 'sheet/%s/' % (sheet_id,))

    @classmethod
    def api_url(cls, username, sheet_id):
        return urljoin(cls.sheet_page(username, sheet_id), 'v%s/json/' % (CURRENT_API_VERSION,))



def snapshot_on_error(test):

    @wraps(test)
    def inner(*args, **kwargs):
        try:
            test(*args, **kwargs)
        except:
            test_object = args[0]

            try:
                filename = test_object.get_dump_filename()
                _debug('screenshot to {}.png'.format(filename))
                test_object.browser.get_screenshot_as_file(filename + '.png')
                _debug('page source dump  to {}.html'.format(filename))
                with open(filename + '.html', 'w') as f:
                    f.write(test_object.browser.page_source.encode('utf8'))
                _debug('page text dump  to {}.txt'.format(filename))
                with open(filename + '.txt', 'w') as f:
                    body_text = test_object.browser.find_element_by_tag_name('body').text
                    f.write(body_text.encode('utf8'))
            except:
                _debug('Exception writing screenshots')
            raise
    return inner


def humanesque_delay(length=DEFAULT_TYPING_WAIT):
    time.sleep(length)


def humanise_with_delay(action):
    @wraps(action)
    def inner(*args, **kwargs):
        humanesque_delay()
        result = action(*args, **kwargs)
        humanesque_delay()
        return result
    return inner


class Bounds(object):
    def __init__(self, width, height, top, left):
        self.width = width
        self.height = height
        self.top = top
        self.left = left

    bottom = property(lambda self: self.top + self.height)

    right = property(lambda self: self.left + self.width)


RGB_RE = re.compile('^rgba?\((\d+), (\d+), (\d+)(, (\d+))?\)')

def convert_rgb_to_hex(value):
    match = RGB_RE.match(value)
    r, g, b = match.group(1), match.group(2), match.group(3)
    return '#%X%X%X' % (int(r), int(g), int(b))


class FunctionalTest(StaticLiveServerTestCase):
    user_count = 1

    def wait_for(
        self, condition_function, msg_function,
        timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT, allow_exceptions=False
    ):
        start = time.time()
        end = start + timeout_seconds
        exception_raised = False
        tries = 0
        while tries < 2 or time.time() < end:
            _debug('Waiting for {}'.format(msg_function()[:30]))
            try:
                tries += 1
                if condition_function():
                    return
                exception_raised = False
            except Exception, e:
                if not allow_exceptions:
                    raise e
                exception_raised = True
            time.sleep(0.1)
        if exception_raised:
            raise
        self.fail("Timeout waiting for condition: %s" % (msg_function(),))

    def get_dump_filename(self):
        timestamp = datetime.datetime.now().isoformat().replace(':', '.')[:19]
        return '{folder}/{test_id}-{timestamp}'.format(
            folder=SCREEN_DUMP_LOCATION,
            test_id=self.id(),
            timestamp=timestamp
        )

    session_keys = {}

    def create_users(self):
        for username in self.get_my_usernames():
            user = User.objects.create(username=username)
            user.set_password('p4ssw0rd')
            user.save()
            profile = user.get_profile()
            profile.has_seen_sheet_page = True
            profile.save()

            # create sessions we can use for login too
            session = SessionStore()
            session[SESSION_KEY] = user.pk
            session[BACKEND_SESSION_KEY] = settings.AUTHENTICATION_BACKENDS[0]
            session[HASH_SESSION_KEY] = user.get_session_auth_hash()
            session.save()
            self.session_keys[username] = session.session_key



    def setUp(self):
        self.create_users()
        _debug("%s ##### Running test %s" % (datetime.datetime.now(), self.id()))
        self.browser = webdriver.Firefox()
        self.browser.implicitly_wait(DEFAULT_WAIT_FOR_TIMEOUT)
        self.browser.set_window_size(1024, 768)


    def tearDown(self):
        _debug('quitting browser')
        self.browser.quit()
        _debug("%s ##### Finished test %s" % (datetime.datetime.now(), self.id()))


    def login(
        self, username=None, password=USER_PASSWORD, manually=False
    ):
        if username is None:
            username = self.get_my_username()

        if manually:
            self.get_element('id=id_username').clear()
            self.get_element('id=id_password').clear()
            self.get_element('id=id_username').send_keys(username)
            self.get_element('id=id_password').send_keys(password)
            self.click_link('id_login')
            return

        session_key = self.session_keys[username]
        ## to set a cookie we need to first visit the domain.
        ## 404 pages load the quickest!
        self.browser.get(urljoin(Url.ROOT, "/404_no_such_url/"))
        self.browser.add_cookie(dict(
            name=settings.SESSION_COOKIE_NAME,
            value=session_key,
            path='/',
        ))
        self.go_to_url(Url.ROOT)


    def logout(self):
        self.go_to_url(Url.LOGOUT)


    def get_element(self, locator):
        if locator.startswith('css='):
            return self.browser.find_element_by_css_selector(locator[4:])
        elif locator.startswith('id='):
            return self.browser.find_element_by_id(locator[3:])



    def is_element_focused(self, locator):
        element = self.get_element(locator)
        focused_element = self.browser.switch_to_active_element()
        return element == focused_element


    def is_element_present(self, locator):
        try:
            self.get_element(locator)
            return True
        except NoSuchElementException:
            return False


    def get_text(self, locator):
        return self.get_element(locator).text


    def get_value(self, locator):
        return self.get_element(locator).get_attribute('value')


    def human_key_press(self, key_code):
        _debug('pressing key %r' % (key_code,))
        self.browser.switch_to_active_element().send_keys(key_code)


    @contextmanager
    def key_down(self, key_code):
        _debug('key down %r' % (key_code,))
        self.browser.switch_to_active_element().send_keys(key_code)
        ActionChains(self.browser).key_down(key_code).perform()
        yield
        # apparently there's no need for a key up??
        # ActionChains(self.browser).key_up(key_code).perform()


    def click_to_and_blur_from(self, click_to_locator, blur_from_locator):
        self.selenium.fire_event(blur_from_locator, 'blur')
        self.selenium.click(click_to_locator)


    def get_element_bounds(self, locator):
        return Bounds(
            self.selenium.get_element_width(locator),
            self.selenium.get_element_height(locator),
            self.selenium.get_element_position_top(locator),
            self.selenium.get_element_position_left(locator)
        )


    def get_css_property(self, jquery_locator, property_name):
        property_value = self.selenium.get_eval('window.$("%s").css("%s")' % (jquery_locator, property_name))
        if property_value == 'rgba(0, 0, 0, 0)': # transparent in chrome
            return 'transparent'
        if property_value.startswith('rgb'):
            property_value = convert_rgb_to_hex(property_value)
        if property_value.startswith('#'):
            property_value = property_value.upper()
            if len(property_value) == 4:
                _, r, g, b = property_value
                property_value = '#%s%s%s%s%s%s' % (r, r, g, g, b, b)
        return property_value


    def assert_urls_are_same(self, actual, expected):
        loc = self.browser.current_url
        canonicalised_actual = urljoin(loc, actual)
        canonicalised_expected = urljoin(loc, expected)
        self.assertEquals(canonicalised_actual, canonicalised_expected)


    def assert_HTTP_error(self, url, error_code):
        self.browser.get(url)
        possible_error_locators = ('id=summary', 'id=id_server_error_title')
        for error_locator in possible_error_locators:
            if self.is_element_present(error_locator) and str(error_code) in self.get_text(error_locator):
                return
        self.fail('%d not raised, got: %s' % (error_code, self.browser.title))


    def assert_redirects(self, from_url, to_url):
        self.go_to_url(from_url)
        self.assert_urls_are_same(
            urlunparse(urlparse(self.browser.current_url)[:4] + ('', '')),
            to_url
        )

    def is_element_enabled(self, element_id):
        #self.selenium.get_attribute is unreliable (Harry, Jonathan)
        disabled = self.selenium.get_eval('window.$("#%s").attr("disabled")' % (element_id,))
        return disabled not in ("true", "disabled")


    def wait_for_element_presence(
        self, locator, present=True, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        if present:
            failure_message = "Element %s to be present" % (locator, ),
        else:
            failure_message = "Element %s to not exist" % (locator, ),
        self.wait_for(
            lambda: self.is_element_present(locator) == present,
            lambda: failure_message,
            timeout_seconds=timeout_seconds
        )


    def wait_for_element_to_appear(self, locator, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for_element_presence(locator, True, timeout_seconds)


    def wait_for_element_text(self, locator, text, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for(
            lambda: self.get_text(locator) == text,
            lambda: "Element %s to contain text %r. Contained %r" % (locator, text, self.get_text(locator)),
            timeout_seconds=timeout_seconds
        )


    def wait_for_element_visibility(self, locator, visibility, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for(
            lambda : self.selenium.is_visible(locator) == visibility,
            lambda : "Element %s to become%svisible" % (locator, visibility and ' ' or ' in'),
            timeout_seconds=timeout_seconds
        )


    def get_url_with_session_cookie(self, url, data=None):
        opener = urllib2.build_opener()
        session_cookie = self.selenium.get_cookie_by_name('sessionid')
        opener.addheaders.append(('Cookie', 'sessionid=%s' % (session_cookie, )))
        if data is None:
            return opener.open(url)
        else:
            encoded_data = urllib.urlencode(data)
            return opener.open(url, encoded_data)


    def create_new_sheet(self, username=None, manually=False):
        if username is None:
            username = self.get_my_username()
        user = User.objects.get(username=username)
        sheet = Sheet(owner=user)
        sheet.save()
        self.browser.get(Url.sheet_page(username, sheet.id))
        return sheet.id



    def login_and_create_new_sheet(self, username=None):
        self.login(username=username)
        return self.create_new_sheet(username=username)


    def get_my_usernames(self):
        usernames = []
        for user_index in range(self.user_count):
            capture_test_details = re.compile(r'test_(\d+)_[^\.]*\.[^\.]*\.test_(.*)$')
            match = re.search(capture_test_details, self.id())
            test_task_id = match.group(1)
            test_method_name = match.group(2)
            test_method_hash = hashlib.md5(test_method_name).hexdigest()[:7]

            usernames.append(("tstusr_%s_%s" % (test_task_id, test_method_hash))[:29] + str(user_index))
        return usernames


    def get_my_username(self):
        return self.get_my_usernames()[0]


    def _check_page_link_home(self):
        if self.browser.current_url.startswith(Url.DOCUMENTATION):
            return

        link = None
        for possible_id in ('id_small_header_logo', 'id_big_logo'):
            try:
                link = self.browser.find_element_by_xpath(
                    "//a[img[@id='{img_id}']]".format(img_id=possible_id)
                )
                self.assertEqual(link.get_attribute('href'), Url.ROOT)
                return
            except NoSuchElementException:
                pass

        self.fail("Could not find a logo that is also a link on page {}".format(
            self.browser.current_url
        ))


    def check_page_load(self, link_destination=None):
        self._check_page_link_home()


    def go_to_url(self, url):
        _debug('going to url ' + url)
        self.browser.get(url)
        self.check_page_load(url)


    def refresh_sheet_page(self):
        self.browser.refresh()
        self.wait_for_grid_to_appear()


    def click_link(self, element_id):
        link = self.browser.find_element_by_id(element_id)
        link.click()


    def set_sheet_name(self, name):
        self.selenium.click('id=id_sheet_name')
        self.wait_for(
            lambda: self.is_element_present('id=edit-id_sheet_name'),
            lambda: 'editable sheetname to appear')
        self.selenium.type('id=edit-id_sheet_name', name)
        self.human_key_press('\n')
        self.wait_for(
            lambda: self.get_text('id=id_sheet_name') == name,
            lambda: 'sheet name to be updated'
        )


    def assert_sends_to_login_page(self, requested_url):
        self.assert_redirects(requested_url, Url.LOGIN)


    def assert_sends_to_root_page(self, requested_url):
        self.assert_redirects(requested_url, Url.ROOT)


    def assert_page_title_contains(self, link_url, title):
        original_page = self.browser.current_url
        self.go_to_url(link_url)
        self.assertTrue(title in self.browser.title)
        self.go_to_url(original_page)


    def assert_has_useful_information_links(self):
        self.browser.find_elements_by_link_text('Terms & Conditions')
        self.browser.find_elements_by_link_text('Privacy Policy')
        self.browser.find_elements_by_link_text('Contact Us')


    def get_cell_css(self, column, row, must_be_active=False):
        active_classes = ''
        if must_be_active:
            active_classes = '.active'
        return 'div.slick-row[row="%d"] div.slick-cell.c%d%s' % (
            row - 1, column, active_classes
        )


    def get_cell_locator(self, column, row, must_be_active=False):
        return 'css=%s' % (self.get_cell_css(column, row, must_be_active),)


    def get_cell_formatted_value_locator(self, column, row, raise_if_cell_missing=True):
        cell_css = self.get_cell_css(column, row)
        if not self.is_element_present('css=%s' % (cell_css,)):
            if raise_if_cell_missing:
                raise Exception("Cell not present at %s, %s" % (column, row))
            else:
                return None
        return 'css=%s span.grid_formatted_value' % (cell_css,)



    cell_editor_css = 'input.editor-text'

    def get_active_cell_editor_locator(self):
        return 'css={}'.format(self.cell_editor_css)


    def get_cell_editor_locator(self, column, row):
        cell_css = self.get_cell_css(column, row)
        return 'css=%s %s' % (cell_css, self.cell_editor_css)


    def get_cell_editor(self):
        return self.get_element(self.get_active_cell_editor_locator())


    def is_cell_visible(self, column, row):
        tries = 0
        while tries < 4:
            try:
                return 'true' == self.selenium.get_eval(dedent(
                    '''
                        (function () {
                            var viewport = window.grid.getViewport();
                            if (viewport.top > %(row)s || %(row)s > viewport.bottom) {
                                return false;
                            }

                            var $canvasDiv = window.$('div.grid-canvas');
                            var $viewportDiv = window.$('div.slick-viewport');
                            var viewableLeft = -$canvasDiv.position().left;
                            var viewableRight = viewableLeft + $viewportDiv.width();
                            var $currentCell = window.$('%(current_cell_css)s');
                            var currentCellLeft = $currentCell.position().left;
                            var currentCellRight = currentCellLeft + $currentCell.outerWidth();
                            if (viewableLeft > currentCellLeft || currentCellRight > viewableRight) {
                                return false;
                            }

                            return true;
                        })()
                    ''' % dict(row=row, col=column, current_cell_css=self.get_cell_css(column, row) )
                ) )
            except:
                time.sleep(1)
                tries += 1

        self.fail("Could not check for cell visibility at %s, %s after %s tries" % (column, row, tries))


    def assert_cell_visible(self, column, row):
        self.assertTrue(
            self.is_cell_visible(column, row),
            'cell %s, %s not visible' % (column, row)
        )


    def wait_for_cell_to_be_visible(
        self, column, row, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        self.wait_for(
            lambda: self.is_cell_visible(column, row),
            lambda: "Cell at %s, %s to become visible" % (column, row),
            allow_exceptions=True,
            timeout_seconds=timeout_seconds
        )


    def get_formula_bar_id(self):
        return "id_formula_bar"


    def get_formula_bar_locator(self):
        return "id=%s" % (self.get_formula_bar_id(),)


    def is_formula_bar_enabled(self):
        return self.is_element_enabled(self.get_formula_bar_id())


    def scroll_cell_row_into_view(self, column, row):
        self.browser.execute_script(
            'window.grid.scrollRowIntoView({row}, true);'.format(row=row - 1)
        )
        self.wait_for_element_to_appear(self.get_cell_locator(column, row))


    def go_to_cell(self, column, row):
        self.selenium.get_eval(
            'window.grid.gotoCell(%s, %s, false)' % (row - 1, column))
        self.wait_for_element_to_appear(self.get_cell_locator(column, row))


    @humanise_with_delay
    def click_on_cell(self, column, row):
        self.scroll_cell_row_into_view(column, row)
        self.get_element(self.get_cell_locator(column, row)).click()


    def select_range_with_shift_click(self, start, end):
        self.click_on_cell(*start)
        with self.key_down(key_codes.SHIFT):
            self.click_on_cell(*end)
        self.assert_current_selection(start, end)


    def mouse_drag(self, cell_from, cell_to):
        from_locator = self.get_cell_locator(*cell_from)
        to_locator = self.get_cell_locator(*cell_to)

        pixel_offset = "10,30"
        #pixel offset fixes selenium weird tendency to click too far north-west.
        #may cause problems if column widths are reduced...

        self.selenium.mouse_down_at(from_locator, pixel_offset)
        humanesque_delay(1)
        self.selenium.mouse_move_at(from_locator, pixel_offset)
        humanesque_delay(1)
        self.selenium.mouse_move_at(to_locator, pixel_offset)
        humanesque_delay(1)
        self.selenium.mouse_up_at(to_locator, pixel_offset)
        humanesque_delay(1)


    def assert_current_selection(self, topleft, bottomright, thoroughly=True):
        if thoroughly:
            for row in range(topleft[1],bottomright[1] + 1):
                for col in range(topleft[0],bottomright[0] + 1):
                    locator = self.get_cell_locator(col, row) + '.selected'
                    self.wait_for_element_to_appear(locator)
        else:
            topleft_locator = self.get_cell_locator(*topleft) + '.selected'
            bottomright_locator = (
                self.get_cell_locator(*bottomright) + '.selected'
            )
            self.wait_for_element_to_appear(topleft_locator)
            self.wait_for_element_to_appear(bottomright_locator)


    def open_cell_for_editing(self, column, row):
        self.scroll_cell_row_into_view(column, row)
        ActionChains(self.browser).double_click(
            self.get_element(self.get_cell_locator(column, row))
        ).perform()
        self.wait_for_cell_to_enter_edit_mode(column, row)


    def type_into_cell_editor_unhumanized(self, text):
        self.get_cell_editor().send_keys(text)


    @humanise_with_delay
    def enter_cell_text(self, col, row, text):
        self.enter_cell_text_unhumanized(col, row, text)


    def enter_cell_text_unhumanized(self, col, row, text):
        self.open_cell_for_editing(col, row)
        self.type_into_cell_editor_unhumanized(text)
        self.type_into_cell_editor_unhumanized('\n')
        # self.wait_for_cell_to_contain_formula(text)


    def get_current_cell(self):
        row = int(self.browser.execute_script(
            'return window.grid.getActiveCell().row;')
        ) + 1
        column = int(self.browser.execute_script(
            'return window.grid.getActiveCell().cell;'
        ))
        return column, row


    def get_cell_text(self, column, row):
        self.scroll_cell_row_into_view(column, row)
        text = self.get_text(self.get_cell_locator(column, row))
        return text


    def get_cell_editor_content(self):
        return self.get_cell_editor().get_attribute('value')


    def get_cell_shown_formula_locator(self, column, row, raise_if_cell_missing=True):
        cell_css = self.get_cell_css(column, row)
        if not self.is_element_present('css=%s' % (cell_css,)):
            if raise_if_cell_missing:
                raise Exception("Cell not present at %s, %s" % (column, row))
            else:
                return None
        return 'css=%s span.grid_formula' % (cell_css,)


    def get_cell_shown_formula(self, column, row, raise_if_cell_missing=True):
        formula_locator = self.get_cell_shown_formula_locator(
            column, row, raise_if_cell_missing
        )
        if not self.is_element_present(formula_locator):
            return None

        formula = self.get_text(formula_locator)
        return formula


    def assert_cell_shown_formula(self, column, row, formula):
        self.assertEquals(self.get_cell_shown_formula(column, row), formula)


    def wait_for_cell_shown_formula(self, column, row, formula, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        def generate_failure_message():
            return (
                "cell %d, %d to show formula '%s', was %r -- text is %r" % (
                column, row, formula, self.get_cell_shown_formula(column, row), self.get_cell_text(column, row))
            )

        self.wait_for(
            lambda : self.get_cell_shown_formula(column, row, raise_if_cell_missing=False) == formula,
            generate_failure_message,
            allow_exceptions=True,
            timeout_seconds=timeout_seconds
        )


    def wait_for_cell_to_contain_formula(self, column, row, formula):
        self.open_cell_for_editing(column, row)
        self.wait_for_cell_editor_content(formula)
        self.get_cell_editor().send_keys('\n')


    error_img_locator = 'id=id_{col}_{row}_error'

    def get_cell_error(self, column, row):
        if self.is_element_present(self.error_img_locator.format(col=column, row=row)):
            return self.get_element(self.error_img_locator.format(col=column, row=row)).get_attribute('title')


    def assert_cell_has_error(self, column, row, error_text):
        self.wait_for_element_to_appear(self.error_img_locator.format(col=column, row=row))
        self.assertEquals(self.get_cell_error(column, row), error_text)


    def assert_cell_has_no_error(self, column, row):
        self.assertFalse(
            self.is_element_present(self.error_img_locator.format(col=column, row=row)),
            'Error present for (%d, %d)' % (column, row)
        )


    def assert_cell_is_current_but_not_editing(self, col, row):
        self.wait_for_cell_to_become_active(col, row)
        self.assertFalse(
            self.is_element_focused(self.get_cell_editor_locator(col, row))
        )


    def assert_cell_is_current_and_is_editing(self, col, row):
        self.wait_for_cell_to_become_active(col, row)
        self.assertTrue(
            self.is_element_focused(self.get_cell_editor_locator(col, row))
        )


    def wait_for_cell_value(
        self, column, row, value_or_regex,
        timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        _debug('waiting for cell {},{} value {}'.format(
            column, row, value_or_regex,
        ))

        def match(text):
            if hasattr(value_or_regex, 'match'):
                return value_or_regex.match(text)
            else:
                return text == value_or_regex

        def cell_shows_value():
            self.last_found_value = self.get_cell_text(column, row)
            return (
                match(self.last_found_value) and
                self.get_cell_shown_formula(
                    column, row, raise_if_cell_missing=False
                ) is None
            )

        def generate_failure_message():
            actual_value = self.last_found_value
            self.last_found_value = None
            actual_formula = ''
            if self.get_cell_shown_formula(column, row) is not None:
                actual_formula = self.last_found_value
                actual_value = ''
            actual_error = self.get_cell_error(column, row)

            return (
                "Cell at (%s, %s) to become %r "
                "(value=%r, shown formula=%r, error=%r)" % (
                    column, row, value_or_regex,
                    actual_value, actual_formula, actual_error)
            )

        self.last_found_value = None
        try:
            self.wait_for(
                cell_shows_value,
                generate_failure_message,
                timeout_seconds=timeout_seconds,
                allow_exceptions=True
            )
        finally:
            _debug('finished waiting for cell value')


    def wait_for_cell_to_become_active(
        self, column, row, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        locator = self.get_cell_locator(column, row, must_be_active=True)
        self.wait_for(
            lambda: self.is_element_present(locator),
            lambda: "Cell at (%s, %s) was not active. Selection is: %s" % (
                column, row, self.get_current_cell()
            ),
            timeout_seconds=timeout_seconds
        )


    def wait_for_cell_to_enter_edit_mode(
        self, column, row, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        self.wait_for_cell_to_become_active(column, row)
        full_editor_locator = self.get_cell_editor_locator(column, row)
        self.wait_for(
            lambda: self.is_element_focused(full_editor_locator),
            lambda: "Editor at (%s, %s) to get focus" % (column, row),
            timeout_seconds=timeout_seconds
        )


    def wait_for_cell_editor_content(self, content):
        self.wait_for(
            lambda: self.get_cell_editor_content() == content,
            lambda: "Cell editor to become %s (was '%s')" % (
                content, self.get_cell_editor_content()
            ),
        )


    def get_viewport_top(self):
        return int(self.selenium.get_eval(
            'window.grid.getViewport().top'
        ) ) + 1


    def get_viewport_bottom(self):
        return int(self.selenium.get_eval(
            'window.grid.getViewport().bottom'
        ) ) + 1


    def is_spinner_visible(self):
        return (
            self.is_element_present('css=#id_spinner_image')
            and not self.is_element_present('css=#id_spinner_image.hidden')
        )


    def wait_for_spinner_to_stop(self, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for(
            lambda : not self.is_spinner_visible(),
            lambda : "Spinner to disappear",
            timeout_seconds=timeout_seconds
        )


    def wait_for_grid_to_appear(self, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for_element_to_appear(self.get_cell_locator(1, 1), timeout_seconds)


    def get_usercode(self):
        return self.browser.execute_script(
            'return window.editor.session.getValue();'
        ).replace('\r\n', '\n')


    @humanise_with_delay
    def enter_usercode(self, code, commit_change=True):
        self.browser.execute_script(
            "window.editor.session.setValue(%s);" % (
                repr(unicode(code))[1:],
            )
        )
        if commit_change:
            self.human_key_press(Keys.F9)


    def append_usercode(self, code):
        self.enter_usercode("%s\n%s" % (self.get_usercode(), code))


    def prepend_usercode(self, code):
        self.enter_usercode("%s\n%s" % (code, self.get_usercode()))


    def wait_for_usercode_editor_content(
        self, content, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT
    ):
        self.wait_for(
            lambda: self.get_usercode().strip() == content.strip(),
            lambda: (
                'Usercode editor content to become \n'
                + content
                + '\n' + '-=' * 10 + '\nwas:\n'
                + self.get_usercode()
            ),
            timeout_seconds=timeout_seconds
        )


    def sanitise_console_content(self, content):
        # IE has char 13 for return instead of the normal Unix 10.
        # Not sure why it differs from Chrome and Firefox.
        return content.replace('\r', '\n')


    def get_console_content(self):
        content = self.selenium.get_eval('window.$("#id_console").text()')
        return self.sanitise_console_content(content)


    def wait_for_console_content(self, content, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for(
            lambda: content in self.get_console_content(),
            lambda : 'error console to contain "%s" (was "%s")' % (content, self.get_console_content()),
           timeout_seconds=timeout_seconds
        )


    def get_formula_bar_contents(self):
        return self.selenium.get_value(self.get_formula_bar_locator())


    def assert_formula_bar_contains(self, contents):
        self.assertEquals(self.get_formula_bar_contents(), contents)


    def wait_for_formula_bar_contents(self, contents, timeout_seconds=DEFAULT_WAIT_FOR_TIMEOUT):
        self.wait_for(
            lambda : self.get_formula_bar_contents() == contents,
            lambda : 'formula bar to contain "%s" (was "%s")' % (contents, self.get_formula_bar_contents() ),
            timeout_seconds=timeout_seconds
        )

    def click_formula_bar(self):
        self.selenium.click(self.get_formula_bar_locator())
        self.wait_for(
            lambda : self.is_element_focused(self.get_formula_bar_locator()),
            lambda : "Formula bar to gain focus"
        )


    def copy_range(self, start, end):
        self.click_on_cell(*start)
        with self.key_down(key_codes.SHIFT):
            self.click_on_cell(*end)
        self.assert_current_selection(start, end)
        with self.key_down(key_codes.CTRL):
            self.selenium.key_press_native(key_codes.LETTER_C)


    def cut_range(self, start, end):
        self.click_on_cell(*start)
        with self.key_down(key_codes.SHIFT):
            self.click_on_cell(*end)
        self.assert_current_selection(start, end)
        with self.key_down(key_codes.CTRL):
            self.selenium.key_press_native(key_codes.LETTER_X)
        self.wait_for_spinner_to_stop()


    def paste_range(self, start, end=None):
        self.click_on_cell(*start)
        if end:
            with self.key_down(key_codes.SHIFT):
                self.click_on_cell(*end)
        with self.key_down(key_codes.CTRL):
            self.selenium.key_press_native(key_codes.LETTER_V)
        self.wait_for_spinner_to_stop()


    def set_filename_for_upload(self, file_name, field_selector):
        if self.selenium.browserStartCommand == '*firefox':
            self.selenium.focus(field_selector)
            self.selenium.type(field_selector, file_name)
            self.selenium.click(field_selector)
        else:
            def handle_file_dialog():
                time.sleep(2)
                SendKeys.SendKeys('{ENTER}')
                time.sleep(2)
                escaped_filename = file_name.replace('~','{~}')
                SendKeys.SendKeys(escaped_filename)
                SendKeys.SendKeys('{ENTER}')
                time.sleep(2)

            dialog_thread = Thread(target=handle_file_dialog)
            dialog_thread.start()
            self.selenium.click(field_selector)
            self.selenium.focus(field_selector)
            dialog_thread.join()


    def pop_email_for_client(self, email_address, fail_if_none=True, content_filter=None):
        retries = 6
        while retries:
            message = self._pop_email_for_client_once(email_address, content_filter=content_filter)
            if message:
                return message
            else:
                retries -= 1
                if retries == 0:
                    if fail_if_none:
                        self.fail('Email not received')
                time.sleep(5)


    def _pop_email_for_client_once(self, email_address, content_filter=None):
        from imapclient import IMAPClient
        message = None
        messages_to_delete = []
        server = IMAPClient(IMAP_HOST, ssl=True)
        for m_id, parsed_headers, body_text in self.all_emails(server):
            if email_address in parsed_headers['To']:
                body_text = body_text.replace('\r', '')
                body_text = body_text.replace('=\n', '')
                if content_filter is None or content_filter in body_text:
                    message = (
                        parsed_headers['From'],
                        parsed_headers['To'],
                        parsed_headers['Subject'],
                        body_text
                    )
                    messages_to_delete.append(m_id)
        server.delete_messages(messages_to_delete)
        return message


    def clear_email_for_address(self, email_address, content_filter=None):
        from imapclient import IMAPClient
        server = IMAPClient(IMAP_HOST, ssl=True)
        messages_to_delete = []
        for m_id, parsed_headers, body_text in self.all_emails(server):
            if email_address in parsed_headers['To']:
                if content_filter is None or content_filter in body_text:
                    messages_to_delete.append(m_id)
        server.delete_messages(messages_to_delete)


    def all_emails(self, server):
        server.login(IMAP_USERNAME, IMAP_PASSWORD)
        server.select_folder('INBOX')
        messages = server.search(['NOT DELETED'])
        response = server.fetch(messages, ['RFC822.TEXT', 'RFC822.HEADER'])
        parser = Parser()
        for m_id, m in response.items():
            parsed_headers = parser.parsestr(m['RFC822.HEADER'])
            body_text = m['RFC822.TEXT']
            yield (m_id, parsed_headers, body_text)



================================================
FILE: dirigible/fts/tests/test_2521_CodeEditor.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from selenium.webdriver.common.keys import Keys
from textwrap import dedent

from functionaltest import FunctionalTest, snapshot_on_error


class Test_2521_CodeEditor(FunctionalTest):

    def test_code_editor_tabs_and_indents(self):
        # * Harold wants an editor with syntax coloring and other good stuff
        #   instead of a boring textarea

        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He notes that the code editor is an Ace editor (!)
        self.assertTrue(
            self.is_element_present('css=#id_usercode.ace_editor'),
            'editor component not present'
        )

        # * He plays around with the code editor and discovers that
        # tabs are converted to 4 spaces, and it autoindents

        original_code = self.get_usercode()
        self.get_element('id=id_usercode').click()
        self.human_key_press('a')
        self.human_key_press('\n')
        self.human_key_press(Keys.TAB)
        self.human_key_press('b')
        self.human_key_press('\n')
        self.human_key_press('c')
        self.human_key_press('\n')

        four_spaces = '    '
        autoindent = four_spaces
        expected_code_after_typing = (
            '{original_code}a\n'
            '{four_spaces}b\n'
            '{autoindent}c\n'
        ).format(
            original_code=original_code,
            four_spaces=four_spaces,
            autoindent=autoindent
        )
        self.wait_for_usercode_editor_content(expected_code_after_typing)

        # ... undo works
        with self.key_down(Keys.CONTROL):
            self.human_key_press('z')

        with self.key_down(Keys.CONTROL):
            self.human_key_press('z')

        expected_code_after_undo = (
            '{original_code}a\n'
            '{four_spaces}b\n'
        ).format(
            original_code=original_code,
            four_spaces=four_spaces,
        )
        self.wait_for_usercode_editor_content(expected_code_after_undo)

        # ... and redo works
        with self.key_down(Keys.CONTROL):
            self.human_key_press('y')
        with self.key_down(Keys.CONTROL):
            self.human_key_press('y')
        self.wait_for_usercode_editor_content(expected_code_after_typing)

        # and typing normally again is fine
        self.human_key_press('abcabc')
        self.wait_for(
            lambda: 'abcabc' in self.get_usercode(),
            lambda: 'could not find abcabc in {}'.format(self.get_usercode()),
        )



    @snapshot_on_error
    def test_code_editor_shows_errors(self):
        # * Harold makes mistakes when writing Python and wants Dirigible to
        #   tell him about them so he can fix them

        error_locator = 'css=div.ace_gutter-cell.ace_error'

        def assert_error(line, message):
            self.wait_for_element_to_appear(error_locator)
            error = self.get_element(error_locator)
            self.assertEquals(error.text, str(line))
            self.assertEquals(error.get_attribute('title'), message)


        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters a value into the grid
        self.enter_cell_text(1, 1, 'herrrroooo')

        original_usercode = self.get_usercode()

        # * He enters some code that creates a syntax error
        self.prepend_usercode('import sys:')

        # ... and notes that an error appears in the code editor, and the value
        # in the grid is grey because the load_constants in the usercode was
        # never executed.
        self.wait_for_cell_shown_formula(1, 1, 'herrrroooo')

        assert_error(1, 'Syntax error at character 11')

        # * He refreshes the page, just because he's ornery and notes that the
        # grid is intact and the error is marked

        self.refresh_sheet_page()

        self.assert_cell_shown_formula(1, 1, 'herrrroooo')

        assert_error(1, 'Syntax error at character 11')

        # * He deletes his mistake and, the error indicator goes away and the
        #   text ungreys
        self.enter_usercode(original_usercode)
        self.wait_for_cell_value(1, 1, 'herrrroooo')
        self.wait_for_element_presence(error_locator, False)

        # * Not satisfied, he tries a different type of error, this one after
        # the usercode loads the constants.
        original_usercode_lines = len(original_usercode.split('\n'))
        self.append_usercode('x = newvalue')

        # Once again, he notes that his grid survives, an error appears in the
        # right place.  However, this time the cell value is not grey.
        self.wait_for_cell_value(1, 1, 'herrrroooo')
        assert_error(
            original_usercode_lines + 1,
            u"NameError: name \u2019newvalue\u2019 is not defined"
        )


    def get_editor_selected_range(self):
        returned_dict = self.browser.execute_script(dedent(
            """
            var selection = window.editor.getSelectionRange();
            return (
                selection.start.column + ", " + selection.start.row + ", " +
                selection.end.column + ", " + selection.end.row
            );
            """
        ))
        return eval(returned_dict)


    def assert_editor_line_visible(self, line):
        first_visible_row = self.browser.execute_script(
            "return window.editor.getFirstVisibleRow()"
        )
        last_visible_row = self.browser.execute_script(
            "return window.editor.getLastVisibleRow()"
        )
        self.assertLess(int(first_visible_row), line)
        self.assertGreater(int(last_visible_row), line)


    @snapshot_on_error
    def test_code_editor_find_function(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # He enters some long and complicated usercode, which contains the string "123" at a well-known place,
        # and doesn't hit "save".
        code = ""
        for i in range(100):
            code += "a\n"
        code += "abc123def"
        for i in range(100):
            code += "a\n"

        self.enter_usercode(code, commit_change=False)

        # He hits ^F, and types 123 into the resulting dialog.
        self.get_element('id=id_usercode').click()
        with self.key_down(Keys.CONTROL):
            self.human_key_press('f')
        alert = self.browser.switch_to_alert()
        alert.send_keys(123)
        alert.accept()

        # The editor jumps to the "123" bit and selects it.
        self.assertEquals(self.get_editor_selected_range(), (3, 100, 6, 100))

        # The line is, of course, visible.
        self.assert_editor_line_visible(100)



    @snapshot_on_error
    def test_code_editor_go_to_line_function(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # He enters some long and complicated usercode and doesn't hit "save".
        code = ""
        for i in range(200):
            code += "a\n"

        self.enter_usercode(code, commit_change=False)

        # He hits ^L, and types 100 into the resulting dialog.
        self.get_element('id=id_usercode').click()
        with self.key_down(Keys.CONTROL):
            self.human_key_press('l')
        alert = self.browser.switch_to_alert()
        alert.send_keys(100)
        alert.accept()

        # The editor jumps to line 100
        self.assertEquals(self.get_editor_selected_range(), (0, 99, 0, 99))

        # The line is, of course, visible.
        self.assert_editor_line_visible(100)


================================================
FILE: dirigible/fts/tests/test_2525_LoginLogout.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from urlparse import urlparse

from functionaltest import FunctionalTest, snapshot_on_error, Url


class Test_2525_LoginLogout(FunctionalTest):

    user_count = 2

    def assert_login_error_shown(self):
        self.assertEquals(
            self.get_text('id=id_login_error'),
            "The user name or password is incorrect. Please try again."
        )


    def test_login_happy_path(self):
        # Harold logs in
        self.go_to_url(Url.LOGIN)

        # Finally, he enters the correct username and password.
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').clear()
        self.get_element('id=id_username').send_keys(self.get_my_username())
        self.get_element('id=id_password').send_keys('p4ssw0rd')
        self.click_link('id_login')

        # He is taken to a page entitled "XXXX's Dashboard: Dirigible" at the site's root URL.
        self.assertEquals(
            self.browser.title,
            "{}'s Dashboard: Dirigible".format(self.get_my_username())
        )
        _, __, path, ___, ____, _____ = urlparse(self.browser.current_url)
        self.assertEquals(path, '/')

        # He sees links to the terms and conditions and suchlike at the bottom of the page.
        self.assert_has_useful_information_links()

        # On the page is a "Log Out" link
        self.assertEquals(self.get_text('id=id_logout_link'), "Log out")


    @snapshot_on_error
    def test_login(self):
        # Harold goes to a specific URL.
        self.go_to_url(Url.LOGIN)

        print('title')
        # He sees a web page with "Login: Dirigible" in the title bar.
        self.assertEquals(self.browser.title, 'Login: Dirigible')
        welcome_url = self.browser.current_url

        print('focus')
        # and notices that his cursor is in the username field
        self.assertTrue(self.is_element_focused('id=id_username'))

        print('userful info')
        # He sees links to the terms and conditions and suchlike at the bottom of the page.
        self.assert_has_useful_information_links()

        print('links')
        # He sees links to the terms and conditions and suchlike at the bottom of the page.
        # He notices a login link on the page and sees that it leads back to this page
        login_link = self.get_element('css=a#id_login_link')
        self.assertEqual(login_link.get_attribute('href'), Url.LOGIN)

        # There is also a "sign up" link that would take him to the signup page.
        signup_link = self.get_element('css=a#id_signup_link')
        self.assertEqual(signup_link.get_attribute('href'), Url.SIGNUP)

        print('inputs')
        # The page also contains places where he can enter a user name and a password, and
        # a login button.
        self.get_element('css=input#id_username')
        self.get_element('css=input#id_password')
        self.get_element('css=input#id_login[type=submit]')

        print('first click')
        # He enters neither, and clicks the login button.
        self.click_link('id_login')

        # He is taken back to a copy of the login page where he is additionally chided for
        # not entering his details.
        self.assert_login_error_shown()

        # He enters a username but no password
        self.get_element('id=id_username').send_keys('confused_user')
        self.click_link('id_login')

        # He is taken back to a copy of the login page where he is told he must enter a
        # password.  The username is still there.
        self.assert_login_error_shown()
        self.assertEquals(self.get_value('id=id_username'), 'confused_user')

        # He enters a password but no username
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').send_keys('confused_pass')
        self.click_link('id_login')

        # He is taken back to a copy of the login page that patiently reminds him that he
        # should enter a username.  The password is cleared
        self.assert_login_error_shown()
        self.assertEquals(self.get_value('id=id_username'), '')
        self.assertEquals(self.get_value('id=id_password'), '')

        # He enters the wrong username and password
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').clear()
        self.get_element('id=id_username').send_keys('wrong user')
        self.get_element('id=id_password').send_keys('wrong password')
        self.click_link('id_login')

        # He is taken back to a copy of the login page telling him that the username/password
        # combo wasn't recognised.  username stays, password goes
        self.assert_login_error_shown()
        self.assertEquals(self.get_value('id=id_username'), 'wrong user')
        self.assertEquals(self.get_value('id=id_password'), '')

        # He corrects the username, but enters the wrong password
        username = self.get_my_username()
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').clear()
        self.get_element('id=id_username').send_keys(username)
        self.get_element('id=id_password').send_keys('wrong password')
        self.click_link('id_login')

        # He is taken back to a copy of the login page telling him that the username/password
        # combo wasn't recognised.  username stays, password goes
        self.assert_login_error_shown()
        self.assertEquals(self.get_value('id=id_username'), username)
        self.assertEquals(self.get_value('id=id_password'), '')

        # He enters the correct password, but takes the opportunity to make the username
        # incorrect.
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').clear()
        self.get_element('id=id_username').send_keys('wrong user')
        self.get_element('id=id_password').send_keys('p4ssw0rd')
        self.click_link('id_login')

        # He is taken back to a copy of the login page telling him that the username/password
        # combo wasn't recognised.  username stays, password goes
        self.assert_login_error_shown()
        self.assertEquals(self.get_value('id=id_username'), 'wrong user')
        self.assertEquals(self.get_value('id=id_password'), '')

        # Finally, he enters the correct username and password.
        self.get_element('id=id_username').clear()
        self.get_element('id=id_password').clear()
        self.get_element('id=id_username').send_keys(username)
        self.get_element('id=id_password').send_keys('p4ssw0rd')
        self.click_link('id_login')

        # He is taken to a page entitled "XXXX's Dashboard: Dirigible" at the site's root URL.
        self.assertEquals(
            self.browser.title,
            "{}'s Dashboard: Dirigible".format(username)
        )
        _, __, path, ___, ____, _____ = urlparse(self.browser.current_url)
        self.assertEquals(path, '/')

        # He sees links to the terms and conditions and suchlike at the bottom of the page.
        self.assert_has_useful_information_links()

        # On the page is a "Log Out" link
        self.assertEquals(self.get_text('id=id_logout_link'), "Log out")

        # He follows it.
        self.click_link('id_logout_link')

        # He is taken back to the "Login: Dirigible" page he saw at the start of this FT.
        self.assertEquals(self.browser.current_url, welcome_url)
        self.assertEquals(self.browser.title, 'Login: Dirigible')

        # He logs in again
        self.get_element('id=id_username').send_keys(username)
        self.get_element('id=id_password').send_keys('p4ssw0rd')
        self.click_link('id_login')

        # He goes back to the login page and is presented with the option to login
        # and the page also includes 'My account' and 'Logout' links
        self.go_to_url(Url.LOGIN)
        self.get_element('css=input#id_username')
        self.get_element('css=input#id_password')
        self.assertEquals(self.get_text('id=id_logout_link'), "Log out")
        self.assertEquals(self.get_text('id=id_account_link'), "My account")

        # He is satisfied, and calls it a day.


    def test_legacy_dashboard_link_takes_you_to_root_url(self):
        harriet = self.get_my_usernames()[1]
        harold = self.get_my_username()
        harolds_dashboard_url = '/user/%s/' % (harold,)
        harriets_dashboard_url = '/user/%s/' % (harriet,)

        # Before logging in, Harold tries to access his own dashboard using the
        # old-style URL.
        # He gets sent to the root page.
        self.assert_sends_to_root_page(harolds_dashboard_url)

        # Before logging in, Harold tries to access Harriet's dashboard using the
        # old-style URL.
        # He gets redirected to the root page
        self.assert_sends_to_root_page(harriets_dashboard_url)

        # Before logging in, Harold also tries to access a non-existent user's dashboard using the
        # old-style URL.
        # He gets sent to the root page.
        self.assert_sends_to_root_page('/user/non-existent-user/')

        # After logging in, Harold tries to access his own dashboard using the
        # old-style URL.
        # He gets sent to the root page.
        self.login(username=harold)
        self.assert_sends_to_root_page(harolds_dashboard_url)

        # After logging in, Harold tries to access Harriet's dashboard using the
        # old-style URL.
        # He gets sent to the root page.
        self.assert_sends_to_root_page(harriets_dashboard_url)

        # After logging in, Harold also tries to access a non-existent user's dashboard using the
        # old-style URL.
        # He gets sent to the root page.
        self.assert_sends_to_root_page('/user/non-existent-user/')


================================================
FILE: dirigible/fts/tests/test_2528_CreateEditSheet.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from selenium.webdriver.common.keys import Keys
from urlparse import urlparse

from functionaltest import FunctionalTest, snapshot_on_error, Url


class Test_2528_CreateEditSheet(FunctionalTest):
    user_count = 2

    def assert_editing_cell(self, column, row):
        self.assertTrue(self.is_element_present(
            self.get_cell_editor_locator(column, row)
        ))


    @snapshot_on_error
    def test_create_edit_sheet(self):
        # * Harold logs in to Dirigible.
        self.login()

        # * On his dashboard, he notes an option to create a new spreadsheet.
        # He chooses it.
        self.assertEquals(self.get_text('id=id_create_new_sheet'), "Create new sheet...")
        self.click_link('id_create_new_sheet')

        # * He is taken to a web page which has a URL like /user/XXXX/sheet/<num>
        #        where XXXX is his user name
        _, __, path, ___, ____, _____ = urlparse(self.browser.current_url)
        self.assertRegexpMatches(path, '/user/%s/sheet/[0-9]+/' % (self.get_my_username(),))

        # * The page has a grid.
        print('check grid')
        self.assertTrue(self.is_element_present('id=id_grid'))

        # * He sees that the grid is a usable size (at least 100x100)
        print('check grid 2')
        self.wait_for_grid_to_appear()
        print('check width')
        self.assertTrue(self.get_element('id=id_grid').size['width'] >= 100)
        self.assertTrue(self.get_element('id=id_grid').size['height'] >= 100)

        # * Now that the grid is loaded (and so the sheet's name is too), he notices
        #   that the title is something like: XXXX's sheet_name: Dirigible
        sheet_name = self.get_text('id=id_sheet_name')
        self.assertEquals(
            self.browser.title,
            "%s's %s: Dirigible" % (self.get_my_username(), sheet_name)
        )


        # * He sees that the grid is reasonably layed out, and it has a sensible
        #   number of rows and columns (at least 10x10), the columns having
        #   headers A, B, C etc and the rows 1, 2, 3,...
        column_list_css = 'div.slick-header-column span.slick-column-name'

        def get_columns():
            return self.browser.find_elements_by_css_selector(column_list_css)

        ## Check for 10 cols plus one header col
        print('check num cols')
        self.wait_for(
            lambda: len(get_columns()) >= 11,
            lambda: 'column count to become >= 11, was {}'.format(len(get_columns())),
        )

        print('col positions')
        col_header_vertical_positions = []
        for letter in 'ABCDEFG':
            column = self.get_element("css=div.slick-header-column[title={}]".format(letter))
            col_header_vertical_positions.append(column.location['y'])
        self.assertEquals(len(set(col_header_vertical_positions)), 1)

        print('col positions horiz')
        col_header_horizontal_positions = []
        for letter in 'ABCDEFG':
            column = self.get_element("css=div.slick-header-column[title={}]".format(letter))
            col_header_horizontal_positions.append(column.location['x'])
        self.assertEquals(
            col_header_horizontal_positions, sorted(col_header_horizontal_positions)
        )

        print('col headers')
        column_headers = [c.text for c in get_columns()]
        print(column_headers)
        self.assertEquals(''.join(column_headers[:8]), "ABCDEFG")  # starts with one blank

        ## Check for 10 rows plus one header row
        print('rows')
        row_list_css = 'div.slick-row'
        rows = self.browser.find_elements_by_css_selector(row_list_css)
        ## SlickGrid handles the header row for us, so we don't have to check for it
        self.assertGreater(len(rows), 9)
        row_header_vertical_positions = []
        for row in rows:
            row_header_vertical_positions.append(row.location['y'])

        self.assertEquals(row_header_vertical_positions, sorted(row_header_vertical_positions))

        row_header_horizontal_positions = set()
        for row in rows:
            row_header_horizontal_positions.add(row.location['x'])
        self.assertEquals(len(row_header_horizontal_positions), 1)

        row_headers = ''.join(r.text for r in rows)
        self.assertEquals(row_headers[:9], "123456789")

        # * He enters "1" in A1.
        print('enter text')
        self.enter_cell_text(1, 1, '1')
        print('text entered')

        # * When he moves away from the cell, "1" is there
        print('clicking cell')
        self.click_on_cell(2, 2)
        print('cell clicked')

        print('wait for value')
        self.wait_for_cell_value(1, 1, '1')
        print('value waited')

        # * He enters "2" in A2.  Similarly, this persists when he moves away.
        print('enter text')
        self.enter_cell_text(1, 2, '2')
        print('text entered')

        print('clicking cell')
        self.click_on_cell(2, 3)
        print('cell clicked')

        print('wait for value')
        self.wait_for_cell_value(1, 2, '2')
        print('value waited')

        # * He enters "=a1+A2" in A3.  When he moves away, he sees "3"
        self.enter_cell_text(1, 3, '=11+22')
        self.click_on_cell(2, 4)
        self.wait_for_cell_value(1, 3, '33')

        # When he edits the cell again, he is presented with the formula as he entered it
        self.open_cell_for_editing(1, 3)
        self.wait_for_cell_editor_content('=11+22')

        # He moves the cursor left and right while editing and the edited cell does not move
        print('checking arrow keys')
        self.human_key_press(Keys.LEFT)
        self.human_key_press(Keys.RIGHT)
        self.assert_editing_cell(1, 3)

        self.open_cell_for_editing(3, 3)
        self.human_key_press(Keys.LEFT)
        self.human_key_press(Keys.LEFT)
        self.assert_editing_cell(3, 3)

        # * He enters "=a1+A2" (NB case!) in A4.  When he moves away, he sees "3"
        self.enter_cell_text(1, 4, '=a1+A2')
        self.click_on_cell(2, 5)
        self.wait_for_cell_value(1, 4, '3')

        # When he edits the cell again, he is presented with the formula as he entered it
        self.open_cell_for_editing(1, 4)
        self.wait_for_cell_editor_content('=a1+A2')


    def test_new_sheet_not_logged_in(self):
        # * Harold goes to /new_sheet without logging in
        # * He gets redirected to the login page
        self.assert_sends_to_login_page(Url.NEW_SHEET)

        # * He logs in
        self.login(manually=True)

        # * ... and gets take to a new sheet
        url = urlparse(self.browser.current_url)
        self.assertEquals(url.netloc, urlparse(Url.ROOT).netloc)
        self.assertRegexpMatches(url.path, '/user/%s/sheet/[0-9]+/' % (self.get_my_username(),))


    @snapshot_on_error
    def test_access_sheet_with_incorrect_user_id(self):
        ## Create sheet as user 1, for the rest of the test
        harriet = self.get_my_usernames()[1]
        harold = self.get_my_username()
        sheet_id = self.login_and_create_new_sheet(username=harriet)
        self.logout()
        harolds_broken_sheet_url = Url.sheet_page(harold, sheet_id)

        # Before logging in, Harold tries to access one of Harriet's sheets
        # using the wrong direct URL, with his username but the correct sheet ID.
        # He gets a 404
        self.assert_HTTP_error(harolds_broken_sheet_url, 404)

        # After logging in, Harold tries to access one of Harriet's sheets
        # using the wrong direct URL, with his username but the correct sheet ID.
        # He gets a 404.
        self.login(username=harold)
        self.assert_HTTP_error(harolds_broken_sheet_url, 404)


================================================
FILE: dirigible/fts/tests/test_2529_HighlightErrorsInCells.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest


class Test_2529_HighlightErrorsInCells(FunctionalTest):

    def test_highlight_errors_in_cells(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters "=lambda x:x + 1" in A1.
        self.enter_cell_text(2, 3, '=lambda x:x + 1')

        # * and notes that there is an error marked for that cell
        self.assert_cell_has_error(
            2, 3,
            "FormulaError: Error in formula at position 10: unexpected ':'"
        )

        # * He then enters '=my_value' in A2
        self.enter_cell_text(4, 5, '=my_value')

        # * and notes that A2 complains that my_value is not defined
        self.assert_cell_has_error(4, 5, "NameError: name 'my_value' is not defined")

        # * He fixes his errors and notes that the error markers go away
        self.enter_cell_text(2, 3, '=lambda x->x + 1')
        self.enter_cell_text(4, 5, '=10')
        self.wait_for_cell_value(4, 5, '10')

        self.assert_cell_has_no_error(2, 3)
        self.assert_cell_has_no_error(4, 5)




================================================
FILE: dirigible/fts/tests/test_2531_DifficultStuffInCells.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from textwrap import dedent

from functionaltest import FunctionalTest, snapshot_on_error, Url


class Test_2531_DifficultStuffInCells(FunctionalTest):

    @snapshot_on_error
    def test_list_in_cell(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters "=[1, 2, 3]" in A1.
        self.enter_cell_text(1, 1, '=[1, 2, 3]')

        # * When he moves away from the cell, "[1, 2, 3]" is there
        self.click_on_cell(2, 1)
        self.wait_for_cell_value(1, 1, '[1, 2, 3]')

        # * He enters a list comprehension in A2.
        self.enter_cell_text(1, 2, '=[x*2 for x in A1]')
        self.click_on_cell(2, 2)
        self.wait_for_cell_value(1, 2, '[2, 4, 6]')


    def test_dictionary_in_cell(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters "={'key'->'value', 'key2'->3}" in A1.
        self.enter_cell_text(1, 1, "={'key'  ->'value', 'key2'->  3}")

        # * When he moves away from the cell, "{'key':'value', 'key2':3}" is there
        self.click_on_cell(2, 1)
        self.wait_for_cell_value(1, 1, repr({'key':'value', 'key2':3}))


    def test_object_in_cell(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters "=object()" in A1.
        self.enter_cell_text(1, 1, '=object()')
        self.click_on_cell(2, 1)

        # * When he moves away from the cell, the obj is visible
        self.wait_for(
            lambda: self.get_cell_text(1, 1).startswith('<object object at 0x'),
            lambda: 'object to appear in cell')

        # * Feeling perverse, he decides to create his own class and shove it into the grid
        self.prepend_usercode(dedent('''
        class Perverse(object):
            t = 'blah'

        p = Perverse()
        '''))
        self.enter_cell_text(3, 1, '=p')
        self.click_on_cell(3, 4)

        # * He sees the string representation of his new object
        self.wait_for(
            lambda: self.get_cell_text(3, 1).startswith('<Perverse object at 0x'),
            lambda: 'user-defined object to appear in cell')


    def assert_input_roundtrips(self, typed):
        # * He enters an html tag in A1
        self.row += 1
        self.enter_cell_text(1, self.row, typed)
        self.wait_for_cell_value(1, self.row, typed)
        self.open_cell_for_editing(1, self.row)
        self.wait_for_cell_editor_content(typed)

        self.enter_cell_text(2, self.row, '="%s"' % (typed, ))
        self.wait_for_cell_value(2, self.row, '%s' % (typed,))
        self.open_cell_for_editing(2, self.row)
        self.wait_for_cell_editor_content('="%s"' % (typed, ))


    def test_html_chars_escaped(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters html tags and chars that look like escaped html tags
        self.row = 1
        self.assert_input_roundtrips('<br />')
        self.assert_input_roundtrips('fish&chips')
        self.assert_input_roundtrips('&lt;')
        self.assert_input_roundtrips('&gt;')
        self.assert_input_roundtrips('&amp;')


    @snapshot_on_error
    def test_numeric_types(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        self.enter_cell_text(1, 1, '999')
        self.wait_for_cell_value(1, 1, '999')
        self.open_cell_for_editing(1, 1)
        self.wait_for_cell_editor_content('999')
        self.append_usercode("worksheet[1, 2].value = type(worksheet[1, 1].value)")
        self.wait_for_cell_value(1, 2, "<type 'int'>")

        self.enter_cell_text(2, 1, '999.0')
        self.wait_for_cell_value(2, 1, '999.0')
        self.open_cell_for_editing(2, 1)
        self.wait_for_cell_editor_content('999.0')
        self.append_usercode("worksheet[2, 2].value = type(worksheet[2, 1].value)")
        self.wait_for_cell_value(2, 2, "<type 'float'>")


================================================
FILE: dirigible/fts/tests/test_2532_LambdasInCells.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

import re
import time
from urlparse import urlparse
from textwrap import dedent

from browser_settings import SERVER_IP

from functionaltest import FunctionalTest, snapshot_on_error


class Test_2532_LambdasInCells(FunctionalTest):

    @snapshot_on_error
    def test_lambda_in_cell(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters "=lambda x -> x + 1" in A1.
        self.enter_cell_text(1, 1, '=lambda x -> x + 1')

        # * He enters =A1(5) into B1
        self.enter_cell_text(2, 1, '=A1(5)')

        # * and notes that the value in B1 is 6
        self.wait_for_cell_value(2, 1, '6')



================================================
FILE: dirigible/fts/tests/test_2533_Numpy.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest, snapshot_on_error


class Test_2533_Numpy(FunctionalTest):

    @snapshot_on_error
    def test_numpy_tutorial_create_arrays(self):
        # * Harold wants to do the tutorial at http://www.scipy.org/Tentative_NumPy_Tutorial
        #   in Dirigible
        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * At the start of the user code, he imports numpy
        self.prepend_usercode('import numpy')

        # * He creates a numoy array in cell A1
        self.enter_cell_text(1, 1, '=numpy.array([2, 3, 4])')

        # * He sees A1 contains the string array([2, 3, 4])
        self.wait_for_cell_value(1, 1, '[2 3 4]')

        # * He checks the type of the array in A2
        self.enter_cell_text(1, 2, '=type(A1)')
        self.wait_for_cell_value(1, 2, "<type 'numpy.ndarray'>")

        # * He creates a 2-dimensional array in B1
        self.enter_cell_text(2, 1, '=numpy.array([(1.5, 2, 3), (4, 5, 6)])')
        self.wait_for_cell_value(2, 1, "[[ 1.5 2. 3. ] [ 4. 5. 6. ]]")

        # * He has a look at some of the properties of the new array
        self.enter_cell_text(2, 2, '=B1.ndim')
        self.wait_for_cell_value(2, 2, "2")
        self.enter_cell_text(2, 3, '=B1.shape')
        self.wait_for_cell_value(2, 3, "(2, 3)")
        self.enter_cell_text(2, 4, '=B1.dtype')
        self.wait_for_cell_value(2, 4, "float64")
        self.enter_cell_text(2, 5, '=B1.itemsize')
        self.wait_for_cell_value(2, 5, "8")

        # * He creates an array of complex numbers
        self.enter_cell_text(3, 1, '=numpy.array([[1, 2], [3, 4]], dtype=numpy.complex)')
        self.wait_for_cell_value(3, 1, "[[ 1.+0.j 2.+0.j] [ 3.+0.j 4.+0.j]]")

        # * He creates arrays of zeros and ones
        self.enter_cell_text(4, 1, '=numpy.zeros((3, 4))')
        self.wait_for_cell_value(4, 1, "[[ 0. 0. 0. 0.] [ 0. 0. 0. 0.] [ 0. 0. 0. 0.]]")
        self.enter_cell_text(5, 1, '=numpy.ones((2, 3, 4), dtype=numpy.int16)')
        self.wait_for_cell_value(5, 1, "[[[1 1 1 1] [1 1 1 1] [1 1 1 1]] [[1 1 1 1] [1 1 1 1] [1 1 1 1]]]")

        # * He uses arange to create a list of numbers
        self.enter_cell_text(6, 1, '=numpy.arange(10, 30, 5)')
        self.wait_for_cell_value(6, 1, "[10 15 20 25]")

        # * He creates a sequence of floating point numbers
        self.enter_cell_text(7, 1, '=numpy.linspace(0, 2, 9)')
        self.wait_for_cell_value(7, 1, "[ 0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. ]")

        # * He uses arange to create a very large array and notes that Dirigible displays it semi-intelligently
        self.enter_cell_text(8, 1, '=numpy.arange(10000)')
        self.wait_for_cell_value(8, 1, "[ 0 1 2 ..., 9997 9998 9999]")


    @snapshot_on_error
    def test_numpy_tutorial_basic_operations(self):
        # * Harold wants to do the tutorial at http://www.scipy.org/Tentative_NumPy_Tutorial
        #   in Dirigible
        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * At the start of the user code, he imports numpy
        self.prepend_usercode('import numpy')

        # * He deducts one range from another
        self.enter_cell_text(1, 1, '=numpy.array([20, 30, 40, 50])')
        self.enter_cell_text(2, 1, '=numpy.arange(4)')
        self.enter_cell_text(3, 1, '=a1 - B1')
        self.wait_for_cell_value(3, 1, "[20 29 38 47]")

        # * He squares a range
        self.enter_cell_text(3, 2, '=B1**2')
        self.wait_for_cell_value(3, 2, "[0 1 4 9]")

        # * He takes the sine of a range
        self.enter_cell_text(3, 3, '=10*numpy.sin(a1)')
        self.wait_for_cell_value(3, 3, "[ 9.12945251 -9.88031624 7.4511316 -2.62374854]")

        # * Having decided that Dirigible supports the basic operations to his satisfaction,
        #   he skips ahead to check that it works with complex numbers
        self.enter_cell_text(1, 1, '=numpy.ones(3, dtype=numpy.int32)')
        self.enter_cell_text(2, 1, '=numpy.linspace(0, numpy.pi, 3)')
        self.enter_cell_text(2, 2, '=b1.dtype.name')
        self.wait_for_cell_value(2, 2, "float64")
        self.enter_cell_text(3, 1, '=a1+b1')
        self.wait_for_cell_value(3, 1, "[ 1. 2.57079633 4.14159265]")
        self.enter_cell_text(3, 2, '=c1.dtype.name')
        self.wait_for_cell_value(3, 2, "float64")
        self.enter_cell_text(4, 1, '=numpy.exp(c1 * 1j)')
        self.wait_for_cell_value(4, 1, "[ 0.54030231+0.84147098j -0.84147098+0.54030231j -0.54030231-0.84147098j]")
        self.enter_cell_text(4, 2, '=d1.dtype.name')
        self.wait_for_cell_value(4, 2, "complex128")


================================================
FILE: dirigible/fts/tests/test_2534_JsonWorksheets.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

try:
    import simplejson as json
except ImportError:
    import json

from urllib import urlencode
from urllib2 import urlopen

from functionaltest import FunctionalTest, Url


class Test_2534_JsonWorksheets_v0_1(FunctionalTest):

    def enable_json_api_for_sheet(self):
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.selenium.type('id=id_security_form_json_api_key', self.get_my_username())
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)


    def test_simple_json(self):
        # * Harold wants to use Dirigible to run his spreadsheets using
        #   a json-based rest API

        # * He logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # * He enables json api access for the sheet
        self.enable_json_api_for_sheet()

        # * He enters some values and formulae
        self.enter_cell_text(1, 1, '5')
        self.enter_cell_text(1, 2, 'abc')
        self.enter_cell_text(2, 1, '6')
        self.enter_cell_text(3, 1, '=a1 + b1')
        self.wait_for_cell_value(3, 1, '11')
        # * He uses an API call to get the sheet as JSON
        sheet_content = json.load(urlopen(Url.api_url(self.get_my_username(), sheet_id), data=urlencode({'api_key': self.get_my_username()})))

        expected = {
            'name' : 'Sheet %s' % (sheet_id,),
            '1': {
                '1': 5,
                '2': 'abc'
                },
            '2': {
                '1': 6,
                },
            '3': {
                '1': 11
            },
        }
        self.assertEquals(sheet_content, expected)


    def test_simple_json_with_error(self):
        # * Harold wants to use Dirigible to run his spreadsheets using
        #   a json-based rest API, and wants the error-handling to be
        #   well-defined (if perhaps not ideal from a debugging perspective)


        # * He logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # * He enables json api access for the sheet
        self.enable_json_api_for_sheet()

        # * He enters a single formula operating on a single value
        self.enter_cell_text(1, 1, '5')
        self.enter_cell_text(1, 2, '=1/A1')
        self.wait_for_cell_value(1, 2, '0.2')

        # * He uses an API call to get the sheet as JSON, passing in an override
        #   value that he knows will cause an error
        get_params = urlencode({'A1':'0', 'api_key': self.get_my_username()})
        url = '%s?%s' % (Url.api_url(self.get_my_username(), sheet_id), get_params)
        try:
            sheet_content = json.load(urlopen(url))
        except Exception, e:
            self.fail(str(e))

        # * He gets back nothing for the cell which generated an error,
        expected = {
            'name' : 'Sheet %s' % (sheet_id,),
            '1': {
                '1': 0,
            },
        }
        self.assertEquals(sheet_content, expected)


    def test_simple_json_with_overrides_get(self):
        # * Harold wants to use Dirigible to run his spreadsheets using
        #   a json-based rest API, and override the formula of some cells

        # * He logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # * He enables json api access for the sheet
        self.enable_json_api_for_sheet()

        # * He enters some values and formulae
        self.enter_cell_text(1, 1, '5')         # A1
        self.enter_cell_text(1, 2, 'abc')       # A2
        self.enter_cell_text(2, 1, '6')         # B1
        self.enter_cell_text(3, 1, '=a1 + b1')  # C1
        self.wait_for_cell_value(3, 1, '11')

        # * He uses an API call to get the sheet as JSON
        #   but overrides the values of cells using GET params:
        #       B1=11
        #       C2=A1 + 1
        #   this also causes cell C1 to change value, since it
        #   depends on B1
        get_params = urlencode({'2,1':'11', 'C2':'=A1 + 1', 'api_key': self.get_my_username()})
        url = '%s?%s' % (Url.api_url(self.get_my_username(), sheet_id), get_params)
        try:
            sheet_content = json.load(urlopen(url))
        except Exception, e:
            self.fail(str(e))

        expected = {
            'name' : 'Sheet %s' % (sheet_id,),
            '1': {
                '1': 5,
                '2': 'abc'
                },
            '2': {
                '1': 11,
                },
            '3': {
                '1': 16,
                '2': 6
            },
        }
        self.assertEquals(sheet_content, expected)


    def test_simple_json_with_overrides_post(self):
        # * Harold wants to use Dirigible to run his spreadsheets using
        #   a json-based rest API, and override the formula of some cells

        # * He logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # * He enables json api access for the sheet
        self.enable_json_api_for_sheet()

        # * He enters some values and formulae
        self.enter_cell_text(1, 1, '5')         # A1
        self.enter_cell_text(1, 2, 'abc')       # A2
        self.enter_cell_text(2, 1, '6')         # B1
        self.enter_cell_text(3, 1, '=a1 + b1')  # C1
        self.wait_for_cell_value(3, 1, '11')

        # * He uses an API call to get the sheet as JSON
        #   but overrides the values of cells using POST params:
        #       B1=11
        #       C2=A1 + 1
        #   this also causes cell C1 to change value, since it
        #   depends on B1
        url = Url.api_url(self.get_my_username(), sheet_id)
        post_params = urlencode({'2,1':'11', 'C2':'=A1 + 1', 'api_key': self.get_my_username()})
        try:
            sheet_content = json.load(urlopen(url, data=post_params))
        except Exception, e:
            self.fail(str(e))

        expected = {
            'name' : 'Sheet %s' % (sheet_id,),
            '1': {
                '1': 5,
                '2': 'abc'
                },
            '2': {
                '1': 11,
                },
            '3': {
                '1': 16,
                '2': 6
            },
        }
        self.assertEquals(sheet_content, expected)



================================================
FILE: dirigible/fts/tests/test_2535_RunWorksheetSerial.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2535_RunWorksheet(FunctionalTest):

    def test_run_worksheet_no_overrides(self):
        # * Harold logs in, creates a new sheet and notes its id
        self.login_and_create_new_sheet()
        target_sheet_url = self.browser.current_url

        # * and enters a few calculations and constants
        self.enter_cell_text(1, 1, '2')
        self.enter_cell_text(1, 2, '3')
        self.enter_cell_text(3, 3, '=A1 + A2')

        # * He creates another new sheet
        self.create_new_sheet()

        # * He enters =run_worksheet('http://...') into A1
        self.enter_cell_text(1, 1, '=run_worksheet("%s")' % (target_sheet_url,))

        # * He enters =A1[3, 3] into A2 and notes that
        self.enter_cell_text(1, 2, '=A1[3, 3].value')

        #   the value from C3 in the first sheet appears there
        self.wait_for_cell_value(1, 2, '5')


    def test_run_worksheet_with_overrides(self):
        # * Harold logs in, creates a new sheet and notes its id
        self.login_and_create_new_sheet()
        target_sheet_url = self.browser.current_url

        # * and enters a few calculations and constants
        self.enter_cell_text(1, 1, '2')
        self.enter_cell_text(1, 2, '3')
        self.enter_cell_text(3, 3, '=A1 + A2')

        # * He creates another new sheet
        self.create_new_sheet()

        # * He enters a run_worksheet with overrides into A1
        overrides = {
            (1, 1): 10,
            (1, 2): '43',
            (1, 3): '=str(A1)'
        }
        overrides_in_formula = repr(overrides).replace(':', '->')
        self.enter_cell_text(1, 1, '=run_worksheet("%s", %s)' % (target_sheet_url, overrides_in_formula))


        #   the value from C3 in the first sheet appears there
        # * He enters =A1[3, 3] into A2 and notes that
        self.enter_cell_text(1, 2, '=A1[3, 3].value')
        self.wait_for_cell_value(1, 2, '53')

        # * He also notes that A3 contains 10
        self.enter_cell_text(2, 2, '=A1[1, 3].value')
        self.wait_for_cell_value(2, 2, '10')


    def test_run_worksheet_with_error(self):
        # * Harold logs in, creates a new sheet and notes its id
        self.login_and_create_new_sheet()
        target_sheet_url = self.browser.current_url

        # * and enters an error
        self.prepend_usercode('import sys:')

        # * He creates another new sheet
        self.create_new_sheet()

        # * He enters a run_worksheet with overrides into A1
        overrides = {
            (1, 1): 10,
            (1, 2): '43',
            (1, 3): '=str(A1)'
        }
        overrides_in_formula = repr(overrides).replace(':', '->')
        self.enter_cell_text(1, 1, '=run_worksheet("%s", %s)' % (target_sheet_url, overrides_in_formula))

        # ... and notes the error shown in A1
        self.assert_cell_has_error(1, 1, 'Exception: run_worksheet: Syntax error at character 11')


================================================
FILE: dirigible/fts/tests/test_2536_ParallelFormulaExecution.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from textwrap import dedent
import re

try:
    import unittest2 as unittest
except ImportError:
    import unittest

from functionaltest import FunctionalTest, snapshot_on_error

took_regex = re.compile('Took ([^s]+)s')

class Test_2536_ParallelFormulaExecution(FunctionalTest):

    def get_last_recalc_time(self):
        match = took_regex.match(self.get_console_content())
        return float(match.group(1))

    @snapshot_on_error
    def test_formulae_executed_in_parallel(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * Harold enters some usercode to provide formulae that take time to calculate
        self.prepend_usercode(dedent('''
        import time
        def slow_product(val1, val2):
            time.sleep(1)
            return val1 * val2
        '''))

        # * he enters a tree of dependent cell formula which use slow_product
        self.enter_cell_text(1, 3, '=slow_product(1, 2)')
        self.enter_cell_text(2, 3, '=slow_product(3, 4)')
        self.enter_cell_text(3, 3, '=slow_product(5, 6)')
        self.enter_cell_text(4, 3, '=slow_product(7, 8)')

        self.enter_cell_text(1, 2, '=slow_product(A3, B3)')
        self.enter_cell_text(2, 2, '=slow_product(C3, D3)')

        self.enter_cell_text(1, 1, '=slow_product(A2, B2)')

        # * and waits for the sheet to calculate
        self.wait_for_cell_value(1, 1, '40320', timeout_seconds=10)

        # * He notes the the recalculation was much faster than he would
        #   expect if the formulae had been run in series
        # Note: There are 7 formulae in 3 dependency 'layers' so we expect
        # the recalc to take about 3sec.
        self.assertTrue(
            self.get_last_recalc_time() < 3.2,
            'calculation took too long - %ss. Parallel broken?' % (self.get_last_recalc_time(),)
        )

    @snapshot_on_error
    def test_run_worksheet_executed_in_parallel(self):
        # * Harold logs in and creates a blank worker sheet
        self.login_and_create_new_sheet()
        worker_sheet_url = self.browser.current_url

        # * He then goes to create a master sheet that makes several calls on the worker
        self.create_new_sheet()
        master_sheet_url = self.browser.current_url

        # * he enters formulae that use the worksheet in a number of run_worksheet calls
        run_worksheet_formula = '=run_worksheet("%s")[1, 1].value' % (worker_sheet_url,)
        for row in range(1, 5):
            self.enter_cell_text(1, row, run_worksheet_formula)


        # * Harold goes back to the worker and enters some usercode to make a recalc slow
        self.go_to_url(worker_sheet_url)
        self.wait_for_grid_to_appear()

        self.prepend_usercode(dedent('''
        import time
        start = time.time()
        x = 1
        while time.time() - start < 10:
            time.sleep(0.5)
            x += 1
        worksheet[1, 1].value = x
        '''))
        self.wait_for_spinner_to_stop(timeout_seconds=15)

        # * He now goes back to the master sheet,
        self.go_to_url(master_sheet_url)
        self.wait_for_grid_to_appear()

        # * He notes the the recalculation was much faster than he would
        #   expect if the run_worksheets had been run in series
        self.wait_for_spinner_to_stop(timeout_seconds=15)
        self.assertTrue(self.get_last_recalc_time() < 19, 'calculation took too long. Parallel recalc broken?')



================================================
FILE: dirigible/fts/tests/test_2537_ErrorsInConsole.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#
from functionaltest import FunctionalTest

from textwrap import dedent

class Test_2537_ErrorsInConsole(FunctionalTest):

    def test_console(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He notes that there is a console on the page
        self.is_element_present('id=id_console')

        original_usercode = self.get_usercode()

        # * He makes an error in usercode
        self.prepend_usercode(dedent('''
        def fn():
            x = new_value
        '''))
        self.append_usercode(dedent('''
        fn()'''))
        fn_call_line = len(self.get_usercode().split('\n'))

        expected_traceback = '''NameError: global name 'new_value' is not defined
    User code line %d
    User code line 2, in fn''' % (fn_call_line,)

        # * ... and notes that a useful traceback appears in the console
        self.wait_for_console_content(expected_traceback)

        # * He removes his error, saves his usercode and notes that the error is no longer shown
        self.enter_usercode(original_usercode)
        self.wait_for_console_content("")


    def test_formula_error_in_console(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters some formulae that contain errors
        self.enter_cell_text(1, 1, '=1/0')
        self.enter_cell_text(3, 2, '=newvalue')
        self.enter_cell_text(2, 4, '={"a": 2}')
        self.assert_cell_has_error(1, 1, 'ZeroDivisionError: float division')

        # * He notes that the errors are reported in the console
        expected_tracebacks = ('''NameError: name 'newvalue' is not defined
    Formula '=newvalue' in C2''',
        '''ZeroDivisionError: float division
    Formula '=1/0' in A1''',
        '''FormulaError: Error in formula at position 6: unexpected ': '
    Formula '={"a": 2}' in B4''')
        for expected_traceback in expected_tracebacks:
            self.wait_for_console_content(expected_traceback)

        # * He removes the errors and notes that the traceback is cleared
        self.enter_cell_text(1, 1, '=1')
        self.enter_cell_text(3, 2, '')
        self.enter_cell_text(2, 4, '={"a"-> 2}')
        self.wait_for_cell_value(1, 1, '1')
        self.wait_for_console_content("")


    def test_formula_errors_precede_usercode_errors_in_console(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters a formula with an error
        self.enter_cell_text(1, 1, '=1/0')

        # * and breaks the usercode after the formulae are run
        self.append_usercode('x = y')
        error_line = len(self.get_usercode().split('\n'))

        # * and notes that the errors are reported in the expected order
        expected_traceback = '''ZeroDivisionError: float division
    Formula '=1/0' in A1
NameError: name 'y' is not defined
    User code line %d''' % (error_line,)
        self.wait_for_console_content(expected_traceback)



================================================
FILE: dirigible/fts/tests/test_2538_ShowStdoutInConsole.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest
from textwrap import dedent


class Test_2538_ShowStdoutInConsole(FunctionalTest):

    def test_stdout_displayed_in_console(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # He adds usercode to print a message
        self.prepend_usercode("print 'greetings'")
        self.append_usercode("print 'puny human'")
        self.wait_for_spinner_to_stop()

        expected = dedent('''
        greetings
        puny human''')[1:]
        self.wait_for_console_content(expected)


    def test_output_interleaved_with_formula_errors(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters usercode that executes evaluate_formulae and outputs a number of times
        self.enter_cell_text(1, 1, '=1/0')
        self.enter_usercode(dedent('''
            for x in range(2):
                print 'at %d' % (x,)
                evaluate_formulae(worksheet)
        '''))
        self.wait_for_spinner_to_stop()

        # * He notes that formula errors and output are correctly interleaved
        self.wait_for_console_content(dedent('''
        at 0
        ZeroDivisionError: float division
            Formula '=1/0' in A1
        at 1
        ZeroDivisionError: float division
            Formula '=1/0' in A1''')[1:])

        #   and that they are correctly coloured
        self.assertEquals(
            self.sanitise_console_content(self.selenium.get_eval("window.$('.console_output_text').text()")),
            dedent('''
                at 0
                at 1
            ''')[1:]
            )

        self.assertEquals(
            self.sanitise_console_content(self.selenium.get_eval("window.$('.console_error_text').text()")),
            dedent('''
                ZeroDivisionError: float division
                    Formula '=1/0' in A1
                ZeroDivisionError: float division
                    Formula '=1/0' in A1
            ''')[1:]
        )



================================================
FILE: dirigible/fts/tests/test_2540_FrontPage.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest, Url

from browser_settings import SERVER_IP


import urllib2
import urlparse

class Test_2540_FrontPage(FunctionalTest):

    def check_url_not_broken(self, url):
        try:
            response = urllib2.urlopen(url)
        except Exception, e:
            self.fail("Error getting url %s: %s" % (url, str(e)))


    def check_links_not_broken_for_tag_attribute(self, tag_xpath, attribute):
        num_tags = self.selenium.get_xpath_count(tag_xpath)
        base_file_location = self.browser.current_url
        for i in range(1, num_tags + 1):
            src = self.selenium.get_attribute("xpath=(%s)[%s]@%s" % (tag_xpath, i, attribute))
            url = urlparse.urljoin(base_file_location, src)
            if not url.startswith("mailto:"):
                self.check_url_not_broken(url)


    def test_front_page_links(self):
        # Harold goes to Dirigible's root page
        self.go_to_url('http://%s/' % (SERVER_IP,))

        # He finds a page with the title  "Welcome to Dirigible"
        self.assertEquals(self.browser.title, 'Welcome to Dirigible')

        # The CSS files are all loaded correctly
        self.check_links_not_broken_for_tag_attribute("//link[@rel='stylesheet']", "href")

        # As are the images
        self.check_links_not_broken_for_tag_attribute("//img", "src")

        # And the links
        self.check_links_not_broken_for_tag_attribute("//a", "href")

        # He notes in particular that the "log in" link take him to the login page.
        front_page = self.browser.current_url
        login_url = self.selenium.get_attribute("xpath=//a[text() = 'Log in']@href")
        self.assert_sends_to_login_page(login_url)
        self.go_to_url(front_page)

        # ...and that the "Pricing", "Find out more", "Watch a video", "Help", "Terms & Conditions",
        # "Privacy Policy", and "Contact Us" take him to pages which have appropriate-looking titles.
        self.assert_page_title_contains(
            self.selenium.get_attribute("xpath=//a[@id='id_pricing_link']@href"),
            'Dirigible Pricing'
        )
        self.assert_page_title_contains(
            self.selenium.get_attribute("xpath=//a[img[@id='id_find_out_more']]@href"),
            'About Dirigible'
        )
        self.assert_page_title_contains(
            self.selenium.get_attribute("xpath=//a[img[@id='id_watch_a_video']]@href"),
            'The Video: Dirigible'
        )
        self.assert_page_title_contains(
            self.selenium.get_attribute("xpath=//a[text() = 'Help']@href"),
            'Dirigible documentation'
        )
        self.assert_has_useful_information_links()

================================================
FILE: dirigible/fts/tests/test_2544_403_404_and_500_pages.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from urlparse import urljoin

from functionaltest import FunctionalTest, PAGE_LOAD_TIMEOUT, Url


class Test_2544_404And500Pages(FunctionalTest):

    user_count = 2


    def test_403(self):
        harriet = self.get_my_usernames()[1]
        self.login_and_create_new_sheet(harriet)
        sheet_url = self.browser.current_url
        self.logout()

        # * Harold goes to a page he should not have access to
        harold = self.get_my_username()
        self.login(harold)
        ## Older versions of Selenium (like the one we use for IE) signal errors
        ## with exceptions.  Newer ones don't.  We handle the former case by
        ## looking at the exception details; for the latter we rely on the checks
        ## of the page text below.
        try:
            self.selenium.open(sheet_url)
        except Exception, e:
            self.assertTrue("403" in str(e), "Error not a 403: %s" % (e,))

        # * He gets an appropriate Dirigible-specific 403 page.
        self.selenium.wait_for_page_to_load(PAGE_LOAD_TIMEOUT)
        self.check_page_load(sheet_url)
        self.assertEquals(self.browser.title, "Access Forbidden: Dirigible")
        self.assertEquals(self.get_text("id=id_server_error_title"), "403 Access Forbidden")
        error_text = self.get_text("id=id_server_error_text")
        self.assertTrue("This page is private and belongs to someone else." in error_text)

        # There is also a link to the Dirigible home page, which he follows and discovers
        # that it works.
        self.click_link('id_link_home')
        self.assertEquals(self.browser.current_url, Url.ROOT)



    def test_404(self):
        # * Harold goes to a non-existent page
        url = urljoin(Url.ROOT, '/notaVALIDpage/')
        ## Older versions of Selenium (like the one we use for IE) signal errors
        ## with exceptions.  Newer ones don't.  We handle the former case by
        ## looking at the exception details; for the latter we rely on the checks
        ## of the page text below.
        try:
            self.selenium.open(url)
        except Exception, e:
            self.assertTrue("404" in str(e), "Error not a 404: %s" % (e,))

        # * He gets an appropriate Dirigible-specific 404 page.
        self.selenium.wait_for_page_to_load(PAGE_LOAD_TIMEOUT)
        self.check_page_load(url)
        self.assertEquals(self.browser.title, "Page not found: Dirigible")
        self.assertEquals(self.get_text("id=id_server_error_title"), "404 Not Found")
        error_text = self.get_text("id=id_server_error_text")
        self.assertTrue("The page that you seek" in error_text)
        self.assertTrue("can't be found; lost in the clouds." in error_text)
        self.assertTrue("Please look somewhere else" in error_text)

        # There is a link to the Dirigible home page, which he follows and discovers
        # that it works.
        self.click_link('id_link_home')
        self.assertEquals(self.browser.current_url, Url.ROOT)



    def test_500(self):
        # * Harold somehow triggers an internal server error
        self.login_and_create_new_sheet()
        url = urljoin(self.browser.current_url, 'set_cell_formula/')
        ## Older versions of Selenium (like the one we use for IE) signal errors
        ## with exceptions.  Newer ones don't.  We handle the former case by
        ## looking at the exception details; for the latter we rely on the checks
        ## of the page text below.
        try:
            self.selenium.open(url)
        except Exception, e:
            self.assertTrue("500" in str(e), "Error not a 500: %s" % (e,))

        # * He gets an appropriate Dirigible-specific 500 page.
        self.selenium.wait_for_page_to_load(PAGE_LOAD_TIMEOUT)
        self.check_page_load(url)
        self.assertEquals(self.browser.title, "Server error: Dirigible")
        self.assertEquals(self.get_text("id=id_server_error_title"), "500 Internal Server Error")
        error_text = self.get_text("id=id_server_error_text")
        self.assertTrue("Sorry, something has gone wrong!" in error_text)
        self.assertTrue("The Dirigible team have notified and will look into the problem ASAP." in error_text)

        # There is a link to the Dirigible home page, which he follows and discovers
        # that it works.
        self.click_link('id_link_home')
        self.assertEquals(self.browser.current_url, Url.ROOT)


================================================
FILE: dirigible/fts/tests/test_2545_PageResizeBehaviour.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest, snapshot_on_error


class Test_2545_PageResizeBehaviour(FunctionalTest):

    @snapshot_on_error
    def test_splitters(self):
        # Harold logs in and creates a new sheet.
        self.login_and_create_new_sheet()

        # He notes that there are splitter bars
        self.assertTrue(self.is_element_present('css=.hsplitbar'))
        self.assertTrue(self.is_element_present('css=.vsplitbar'))

        # He uses the vertical split bar to resize the grid to its minimum width
        self.selenium.drag_and_drop('css=.vsplitbar', '-4000, 0')
        self.assertAlmostEquals(self.selenium.get_element_width('id=id_left_column'), 0, delta=5)
        # and then increases its width a bit
        self.selenium.drag_and_drop('css=.vsplitbar', '40, 0')
        self.assertAlmostEquals(self.selenium.get_element_width('id=id_left_column'), 40, delta=5)

        # He uses the horizontal split bar to shrink the console
        self.selenium.drag_and_drop('css=.hsplitbar', '0, 2000')
        self.assertAlmostEquals(self.selenium.get_element_height('id=id_console_wrap'), 0, delta=5)
        # and then increases its height a bit
        self.selenium.drag_and_drop('css=.hsplitbar', '0, -20')
        self.assertAlmostEquals(self.selenium.get_element_height('id=id_console_wrap'), 20, delta=5)

        # He notes that his splitter positions are restored when he reloads the page
        self.refresh_sheet_page()
        self.wait_for_grid_to_appear()
        self.assertAlmostEquals(self.selenium.get_element_width('id=id_left_column'), 40, delta=5)
        self.assertAlmostEquals(self.selenium.get_element_height('id=id_console_wrap'), 20, delta=5)

        # He uses the vertical split bar to resize the right-hand column to its minimum width
        self.selenium.drag_and_drop('css=.vsplitbar', '4000, 0')
        self.assertAlmostEquals(self.selenium.get_element_width('id=id_right_column'), 0, delta=5)
        # and then increases its width a bit
        self.selenium.drag_and_drop('css=.vsplitbar', '-40, 0')
        self.assertAlmostEquals(self.selenium.get_element_width('id=id_right_column'), 40, delta=5)

        # He uses the horizontal split bar to shrink the editor to zero size, and notes that it disappears
        self.selenium.drag_and_drop('css=.hsplitbar', '0, -2000')
        self.wait_for_element_visibility('id=id_usercode', False)

        # He uses the horizontal split bar to make the editor 25px high, and notes that it is still hidden
        self.selenium.drag_and_drop('css=.hsplitbar', '0, 25')
        self.wait_for_element_visibility('id=id_usercode', False)

        # He uses the horizontal split bar to give the editor and its margins 50px of space, and notes
        # that it is visible and small
        self.selenium.drag_and_drop('css=.hsplitbar', '0, 25')
        self.wait_for_element_visibility('id=id_usercode', True)
        self.assertAlmostEquals(self.selenium.get_element_height('id=id_usercode'), 40, delta=5)


    @snapshot_on_error
    def test_grid_resize(self):
        # Harold logs in a creates a new sheet.
        self.login_and_create_new_sheet()

        # He sees that the bottom of the grid is a specific distance from the bottom of the window,
        # and that the top of the grid is a specific distance from the top of the window.  He notes
        # those distances down.
        grid_bounds = self.get_element_bounds("id=id_grid")
        browser_page_height = int(self.selenium.get_eval("window.document.body.clientHeight"))
        browser_page_width = int(self.selenium.get_eval("window.document.body.clientWidth"))
        original_distance_to_bottom = browser_page_height - grid_bounds.bottom
        original_distance_to_top = grid_bounds.top

        # He resizes the window.
        self.selenium.get_eval("window.resizeTo(%s, %s)" % (browser_page_width - 10, browser_page_height - 10))

        # He notes that the grid is still the same distances from the top and the bottom of the
        # window.
        def get_distance_to_bottom():
            new_grid_bounds = self.get_element_bounds("id=id_grid")
            browser_page_height = int(self.selenium.get_eval("window.document.body.clientHeight"))
            return browser_page_height - new_grid_bounds.bottom
        self.wait_for(
            lambda: get_distance_to_bottom() == original_distance_to_bottom,
            lambda: "Distance to bottom to become %s (was %s)" % (original_distance_to_bottom, get_distance_to_bottom())
        )

        def get_distance_to_top():
            return self.get_element_bounds("id=id_grid").top
        self.wait_for(
            lambda: get_distance_to_top() == original_distance_to_top,
            lambda: "Distance to top to become %s (was %s)" % (original_distance_to_top, get_distance_to_top())
        )


================================================
FILE: dirigible/fts/tests/test_2546_ListSheetsOnDashboard.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest, SERVER_IP, snapshot_on_error

import key_codes


class Test_2546_ListSheetsOnDashboard(FunctionalTest):

    def rename_current_sheet(self, name):
        self.selenium.click('id=id_sheet_name')
        self.wait_for(
            lambda: self.is_element_present('id=edit-id_sheet_name'),
            lambda: 'edit sheetname textbox to appear')
        self.selenium.type('id=edit-id_sheet_name', name)
        self.human_key_press(key_codes.ENTER)
        self.wait_for_element_presence('id=saving-id_sheet_name', False)


    def assert_sheet_is_listed(self, sheet_id, sheet_name=None):
        if sheet_name is None:
            sheet_name = 'Sheet %s' % (sheet_id,)
        expected_url = '/user/%s/sheet/%s/' % (self.get_my_username(), sheet_id)
        link_text = self.get_text(
            'css=a[href="%s"]' % (expected_url,))
            # "xpath=//a[contains(@href, '%s')]" % (expected_url,))
        self.assertEquals(link_text, sheet_name)


    @snapshot_on_error
    def test_list_exists(self):
        # * Harold logs in to Dirigible.
        self.login()

        # * He notes that he is being told that he has no sheets.
        self.assertTrue(
            self.is_element_present('id=id_no_sheets_message'),
            "Could not find 'no sheets' message"
        )

        # * He decides that he wants one, so he clicks on a button to create it.
        sheet1_id = self.create_new_sheet()

        # * He clicks 'my account' and goes back to dashboard page
        # * His new sheet is listed there, with a link to it
        self.click_link('id_account_link')
        self.assert_sheet_is_listed(sheet1_id)

        # He notes that the "no sheets" message is absent.
        self.assertFalse(
            self.is_element_present('id=id_no_sheets_message'),
            "Found 'no sheets' message when it wasn't expected"
        )


        # * He clicks new sheet again
        sheet2_id = self.create_new_sheet()
        # * He renames the second sheet
        self.rename_current_sheet('Snarf')

        # * He clicks 'my account' and goes back to dashboard page
        self.click_link('id_account_link')
        # * Both sheets are listed there
        self.assert_sheet_is_listed(sheet1_id)
        self.assert_sheet_is_listed(sheet2_id, 'Snarf')



================================================
FILE: dirigible/fts/tests/test_2547_EnterDataQuickly.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

import time

from functionaltest import FunctionalTest, snapshot_on_error


class Test_2547_EnterDataQuickly(FunctionalTest):

    @snapshot_on_error
    def test_enter_data_quickly(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters 20 numbers quickly
        for row in range(1, 21):
            self.enter_cell_text_unhumanized(1, row, "%s" % (row,))

        # * He checks that they are all there.
        for row in range(1, 21):
            self.wait_for_cell_value(1, row, "%s" % (row,))


    @snapshot_on_error
    def test_enter_data_quickly_in_batches(self):
        # Running the above test made it clear that it was significantly more
        # likely to drop the last number than any others, so we added the below
        # to increase the likelihood of that particular failure mode.

        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters 20 numbers quickly, taking a brief rest every five numbers
        for row in range(1, 21):
            self.enter_cell_text_unhumanized(1, row, "%s" % (row,))
            if row % 5 == 0:
                time.sleep(2)

        # * He checks that they are all there.
        for row in range(1, 21):
            self.wait_for_cell_value(1, row, "%s" % (row,))



================================================
FILE: dirigible/fts/tests/test_2548_UserCode.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from textwrap import dedent

from functionaltest import FunctionalTest, snapshot_on_error


class Test_2548_UserCode(FunctionalTest):

    @snapshot_on_error
    def test_editor_presence(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He notices that there is an Ace code editor on the page, which he
        #   has inexplicably not noticed before.
        self.assertTrue(
            self.is_element_present('css=#id_usercode.ace_editor')
        )

        # * In the editor, there is some interesting-looking code
        self.assertEquals(
            self.get_usercode().strip(),
            dedent(
                '''
                load_constants(worksheet)

                # Put code here if it needs to access constants in the spreadsheet
                # and to be accessed by the formulae.  Examples: imports,
                # user-defined functions and classes you want to use in cells.

                evaluate_formulae(worksheet)

                # Put code here if it needs to access the results of the formulae.
                ''').strip()
        )


    @snapshot_on_error
    def test_preformula_usercode(self):
        # * Harold wants to create a function to use in a cell's formula
        # * He logs in to Dirigible and creates a new sheet.
        self.login_and_create_new_sheet()

        # * He enters the following code into the usercode before the formula code:
        #{{{
        #def addA1(value):
        #    return value + worksheet.A1
        #}}}
        self.enter_usercode(dedent('''
            load_constants(worksheet)

            def addA1(value):
                return value + worksheet[1, 1].value

            evaluate_formulae(worksheet)
        '''))

        # * He enters '1' into A1
        self.enter_cell_text(1, 1, '1')

        # * In cell A4, he enters "=addA1(5)", and gets the result 6.
        self.enter_cell_text(1, 4, '=addA1(5)')
        self.wait_for_cell_value(1, 4, '6')


    @snapshot_on_error
    def test_postformula_usercode(self):
        # * Harold wants to specify code to run after his formulae have been calculated
        # * He logs in to Dirigible and creates a new sheet.
        self.login_and_create_new_sheet()

        # * He enters 2 into cell A3
        self.enter_cell_text(1, 3, '2')

        # * He adds an appropriate line to the end of the usercode, after the
        #   evaluate_formulae call, and applies the change:
        self.enter_usercode(dedent('''
            load_constants(worksheet)

            evaluate_formulae(worksheet)

            worksheet[1, 5].value = 10 + worksheet[1, 3].value
        '''))

        # * He notes that the value "13" appears in A5.
        self.wait_for_cell_value(1, 5, '12')


================================================
FILE: dirigible/fts/tests/test_2549_InterruptedRecalculations.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

import time
from textwrap import dedent

from functionaltest import FunctionalTest, snapshot_on_error


class Test_2549_InterruptedRecalculations(FunctionalTest):

    @snapshot_on_error
    def test_interrupted_recalc_coming_back_handled_correctly(self):
        # Harold logs on and creates a sheet
        self.login_and_create_new_sheet()

        # Harold enters a long-running recalc that finishes by
        # setting a value in the grid
        self.enter_usercode(dedent('''
            import time
            time.sleep(20)
            worksheet[1, 5].value = 1
        '''))

        # While it is running, he realises that there is a shorter
        # algorithm, so he tries that instead.
        time.sleep(1)
        self.enter_usercode(dedent('''
            worksheet[1, 5].value = 2
        '''))

        # Even though the initial longer-running recalc finishes
        # after the second one, the result he sees is from the
        # second one; he concludes that the results of the first
        # one must have been thrown away.
        self.wait_for_cell_value(1, 5, '2')

        # To confirm this to himself, he waits until the first
        # recalc has absolutely definitely finished, and confirms
        # that its results never appear in the grid.
        time.sleep(30)
        self.wait_for_cell_value(1, 5, '2')

        # He then refreshes his web page to make sure that the
        # correct version is current in the database.
        self.refresh_sheet_page()
        self.wait_for_grid_to_appear()
        self.wait_for_cell_value(1, 5, '2')


================================================
FILE: dirigible/fts/tests/test_2550_EditableSheetName.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest
from textwrap import dedent

import key_codes


class Test_2550_EdittableSheetName(FunctionalTest):

    def test_sheet_name_edittable(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He notes that the sheet has a name of the form 'Sheet #xx'
        #   where xx is the sheet id
        sheet_id = self.browser.current_url.split(r'/')[-2]
        self.assertEquals(
            self.get_text('id=id_sheet_name'),
            'Sheet %s' % (sheet_id,))

        # * He mouses over the sheet name and notes that the appearance
        #   changes to indicate that it's editable
        self.selenium.mouse_over('id=id_sheet_name')
        self.wait_for(
            lambda: self.get_css_property('#id_sheet_name', 'background-color') == '#D1D2D4',
            lambda: 'sheet name background to darken')

        # * He moves the mouse away - it changes back
        self.selenium.mouse_out('id=id_sheet_name')
        self.wait_for(
            lambda: self.get_css_property('#id_sheet_name', 'background-color') == 'transparent',
            lambda: 'sheet name background to return to normal')

        # * He clicks on the sheet name, the sheeetname edit textarea appears,
        # and remains when the mouse moves away
        self.selenium.click('id=id_sheet_name')
        self.wait_for(
            lambda: self.is_element_present('id=edit-id_sheet_name'),
            lambda: 'editable sheetname to appear')
        self.selenium.mouse_out('id=id_sheet_name')
        self.assertTrue(self.is_element_present('id=edit-id_sheet_name'))

        # * He types a new sheetname 'margarita', hits return.
        self.selenium.type('id=edit-id_sheet_name', 'margarita')
        self.human_key_press(key_codes.ENTER)

        #   The sheetname is modified
        self.wait_for(
            lambda: self.get_text('id=id_sheet_name') == 'margarita',
            lambda: 'sheet name to be updated'
        )
        # and the title to the page becomes "user's sheet_name: Dirigible"
        self.assertEquals(self.browser.title, "%s's %s: Dirigible" %
            (self.get_my_username(), 'margarita'))

        # * He refreshes the page
        self.refresh_sheet_page()

        #   The new sheetname persists
        self.wait_for(
            lambda: self.get_text('id=id_sheet_name') == 'margarita',
            lambda: 'sheet name to be updated'
        )
        # and the title to the page remains "user's sheet_name: Dirigible"
        self.wait_for(
            lambda: self.browser.title == "%s's %s: Dirigible" % (self.get_my_username(), 'margarita'),
            lambda: 'page title to update'
        )


    def test_changing_sheet_name_should_not_interrupt_recalc_but_still_succeeds(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters usercode that takes a long time to run
        self.enter_cell_text(1, 1, '')
        self.enter_usercode(dedent('''
            import time
            time.sleep(20)
            worksheet[1, 1].value = 'recalced'
        '''))

        # * While the recalc is running, he changes the sheet name
        self.selenium.click('id=id_sheet_name')
        self.wait_for(
            lambda: self.is_element_present('id=edit-id_sheet_name'),
            lambda: 'editable sheetname to appear')
        self.selenium.type('id=edit-id_sheet_name', 'new sheet name')
        self.human_key_press(key_codes.ENTER)

        # * The recalculation finishes normally and his sheet has a new name
        self.wait_for_cell_value(1, 1, 'recalced', timeout_seconds=21)
        self.assertEquals(self.get_text('id=id_sheet_name'), 'new sheet name')

        # * he checks that the new sheetname sticks after a page refresh
        self.refresh_sheet_page()
        self.assertEquals(self.get_text('id=id_sheet_name'), 'new sheet name')





================================================
FILE: dirigible/fts/tests/test_2554_SlicingInFormulae.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest


class Test_2554_SlicingInFormulae(FunctionalTest):

    def test_formulas_work_properly(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # Harold REALLY likes slicing things. We should ensure that
        # he can indulge his axe-murderer side
        self.enter_cell_text(1, 1, '=[0, 10, 20, 30, 40]')
        self.enter_cell_text(1, 2, '=A1[1->3]')
        self.wait_for_cell_value(1, 2, '[10, 20]')

        self.enter_cell_text(2, 1, 'a string that really needs to be sliced')
        self.enter_cell_text(2, 2, '=B1[->10]')
        self.wait_for_cell_value(2, 2, 'a string t')

        self.enter_cell_text(3, 2, '=B1[9->]')
        self.wait_for_cell_value(3, 2, 'that really needs to be sliced')

        self.enter_cell_text(4, 2, '=B1[-8->]')
        self.wait_for_cell_value(4, 2, 'e sliced')

        self.enter_cell_text(5, 2, '=B1[4->->3]')
        self.wait_for_cell_value(5, 2, 'rgh ayesoele')


================================================
FILE: dirigible/fts/tests/test_2556_BrokenUserCode.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest, snapshot_on_error


class test_2556_BrokenUsercode(FunctionalTest):

    @snapshot_on_error
    def test_newly_entered_formulae_appear_grey_then_results_in_black(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # make recalc slow, so that we can be sure to see cells
        # passing through their intermediate 'sent to server
        # but not yet evaluated' state
        # Set 2,2 to ready to be sure this usercode change is made before
        # proceeding.
        self.prepend_usercode('import time\ntime.sleep(20.0)\nworksheet[2,2].formula="ready"')
        self.wait_for_cell_value(2, 2, 'ready', timeout_seconds=22)

        # check intermediate state then final state after entering a formula
        self.enter_cell_text(1, 2, '=123')
        self.wait_for_cell_shown_formula(1, 2, '=123', timeout_seconds=19)
        self.wait_for_cell_value(1, 2, '123', timeout_seconds=30)


    def test_broken_usercode_returns_as_much_as_it_can(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        original_usercode = self.get_usercode()

        # * He enters a constant and a formula in the sheet
        self.enter_cell_text(1, 1, 'abc')
        self.enter_cell_text(1, 2, '=123')
        self.wait_for_cell_value(1, 2, '123')

        # * He adds a usercode error before the constants get calculated
        self.prepend_usercode('x=1/0')

        self.enter_cell_text(2, 1, 'def')
        self.enter_cell_text(2, 2, '=456')
        self.wait_for_cell_shown_formula(2, 2, '=456')

        self.assert_cell_shown_formula(1, 1, 'abc')
        self.assert_cell_shown_formula(1, 2, '=123')
        self.assert_cell_shown_formula(2, 1, 'def')
        self.assert_cell_shown_formula(2, 2, '=456')

        # * He adds a usercode error between constants and formulae

        def insert(text):
            insertion_point = original_usercode.find('evaluate_formulae(worksheet)')
            return "%s\n%s\n%s" % (
                original_usercode[:insertion_point],
                text,
                original_usercode[insertion_point:],
            )

        usercode = insert('x=1/0\n')
        self.enter_usercode(usercode)

        self.enter_cell_text(3, 1, 'ghi')
        self.enter_cell_text(3, 2, '=789')
        self.wait_for_cell_shown_formula(3, 2, '=789')

        self.assertEquals(self.get_cell_text(1, 1), 'abc')
        self.assert_cell_shown_formula(1, 2, '=123')
        self.assertEquals(self.get_cell_text(2, 1), 'def')
        self.assertEquals(self.get_cell_text(2, 2), '=456')
        self.assertEquals(self.get_cell_text(3, 1), 'ghi')
        self.assertEquals(self.get_cell_text(3, 2), '=789')

        # * He adds a usercode error after formulae
        self.enter_usercode(original_usercode)
        self.append_usercode('x=1/0')

        self.enter_cell_text(4, 1, 'jkl')
        self.enter_cell_text(4, 2, '=100')
        self.wait_for_cell_value(4, 2, '100')

        self.assertEquals(self.get_cell_text(1, 1), 'abc')
        self.assertEquals(self.get_cell_text(1, 2), '123')
        self.assertEquals(self.get_cell_text(2, 1), 'def')
        self.assertEquals(self.get_cell_text(2, 2), '456')
        self.assertEquals(self.get_cell_text(3, 1), 'ghi')
        self.assertEquals(self.get_cell_text(3, 2), '789')
        self.assertEquals(self.get_cell_text(4, 1), 'jkl')
        self.assertEquals(self.get_cell_text(4, 2), '100')

        # \o/ hooray!



================================================
FILE: dirigible/fts/tests/test_2557_ClickAwaySavesUsercode.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest


class Test_2557_ClickAwaySavesUsercode(FunctionalTest):

    def test_blur_on_edit_textarea_saves_usercode(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters some usercode that sets A1 to 4
        self.selenium.get_eval('window.editor.focus()')
        self.enter_usercode('worksheet[1, 1].value = 4')

        # * He does something to cause a blur event on the editarea textbox
        ## We use fire_event because Selenium does not fire the full event stack
        ## for clicks. If this changes in future Selenium versions, it would be nice
        ## to expand this test to check behaviour for clicking on cells, links and
        ## edit sheet name
        self.selenium.get_eval("window.editor.blur()")

        # * ... and notes that A1 contains 4
        self.wait_for_cell_value(1, 1, '4')


================================================
FILE: dirigible/fts/tests/test_2558_MoreCellsByDefault.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2558_MoreCellsByDefault(FunctionalTest):

    def test_more_cells_by_default(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He notes that the sheet he is presented with has
        #   an elegant sufficiency of rows and columns (1000 rows and 702
        #   (up to ZZ) columns)
        self.scroll_cell_row_into_view(1, 1000)

        row_list_xpath = '//div[contains(@class, "slick-row") and @row=999]'
        row_count = self.selenium.get_xpath_count(row_list_xpath)
        self.assertEquals(row_count, 1, 'fewer than 1000 rows')

        self.scroll_cell_row_into_view(52, 1)
        column_list_xpath = '//div[@class="slick-cell c52"]'

        column_count = self.selenium.get_xpath_count(column_list_xpath)
        self.assertTrue(column_count >= 1, 'fewer than AZ columns')

        self.scroll_cell_row_into_view(1, 1)
        # * The last cell on the grid accepts input as expected
        self.enter_cell_text(52, 1000, 'end of the sheet')

        # * He notes that, since he just typed on the bottom row,
        #   the cell stays in edit mode, so he has to click away
        #   to finish the edit
        self.click_on_cell(51, 999)
        self.wait_for_cell_value(52, 1000, 'end of the sheet')


================================================
FILE: dirigible/fts/tests/test_2559_FitEditorToCells.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2559_FitEditorToCells(FunctionalTest):

    def test_editor_fits_cells(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        cell_locator = self.get_cell_locator(3, 3)
        cell_width = self.selenium.get_element_width(cell_locator)
        cell_height = self.selenium.get_element_height(cell_locator)

        # * He edits a cell and notes that the editor fits the
        #   cell exactly
        self.open_cell_for_editing(3, 3)
        editor_locator = 'css=input.editor-text'
        editor_width = self.selenium.get_element_width(editor_locator)
        editor_height = self.selenium.get_element_height(editor_locator)

        self.assertTrue(cell_width - editor_width <= 6, "cell width: %d, editor width: %d" % (cell_width, editor_width))
        self.assertTrue(cell_height - editor_height <= 6, "cell height: %d, editor height: %d" % (cell_height, editor_height))


================================================
FILE: dirigible/fts/tests/test_2562_ErrorInCellShouldBeClearedByConstants.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest


class test_2562_ErrorInCellShouldBeClearedByConstants(FunctionalTest):

    def test_ConstantsClearCellErrors(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters and error in A1.
        self.enter_cell_text(1, 1, '=1/0')
        self.assert_cell_has_error(1, 1, "ZeroDivisionError: division by zero")

        # * when he overwrites the cell content with a constant
        #   the error disappears
        self.enter_cell_text(1, 1, '123')
        self.assert_cell_has_no_error(1, 1)

        # hooray!



================================================
FILE: dirigible/fts/tests/test_2565_JSONAPIAuth.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from __future__ import with_statement

try:
    import json
except ImportError:
    import simplejson as json
from urllib import urlencode
from urllib2 import urlopen, HTTPError
from urlparse import urljoin, urlparse

# these can't be imported on non-windows machines, but we need to import test
# modules on our *nix integration master without running them, to run the build
try:
    from win32clipboard import OpenClipboard, GetClipboardData, CloseClipboard
    import win32con
except:
    pass

import key_codes
from functionaltest import FunctionalTest, PAGE_LOAD_TIMEOUT, Url


class Test_2565_JSONAPIAuth(FunctionalTest):

    def test_json_api_auth(self):
        # Harold wants to make sure that people only have JSON access to his sheets
        # when he has explicitly granted it.

        # * He logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()
        base_json_url = urljoin(self.browser.current_url, 'v0.1/json/')

        # * He enters some values and formulae
        self.enter_cell_text(1, 1, '5')

        # * He tries to use an API call to get the sheet as JSON, but gets a 403 error.
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url)
        self.assertEquals(mngr.exception.code, 403)

        # * Looking around at the sheet page, he notices a "Security" button.
        self.wait_for_element_to_appear('id=id_security_button')

        # * He sees that the mouseover text on the button indicates that the JSON API is not enabled
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        # * He clicks the button.
        self.selenium.click('id=id_security_button')

        # * A dialog appears; there is an unchecked toggle saying "Allow JSON API access"
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.wait_for_element_visibility('id=id_security_form_json_enabled_checkbox', True)
        self.wait_for_element_visibility('id=id_security_form_json_api_key', True)
        self.wait_for_element_visibility('id=id_security_form_json_api_url', True)

        self.assertFalse(self.is_element_enabled('id_security_form_json_api_key'))
        self.assertFalse(self.is_element_enabled('id_security_form_json_api_url'))

        self.assertEquals(
            self.get_text('css=label[for="id_security_form_json_enabled_checkbox"]'),
            'Allow JSON API access'
        )
        self.assertEquals(self.selenium.get_value('id=id_security_form_json_enabled_checkbox'), 'off')

        # * ... and OK and Cancel buttons
        self.wait_for_element_visibility('id=id_security_form_ok_button', True)
        self.wait_for_element_visibility('id=id_security_form_cancel_button', True)

        # * He checks it.  He notices a textbox giving him an "API key",
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.assertTrue(self.is_element_enabled('id_security_form_json_api_key'))
        api_key = self.selenium.get_value('id=id_security_form_json_api_key')
        api_url = self.selenium.get_value('id=id_security_form_json_api_url')

        # * He also notices that when he clicks on the URL text field, the entire field is selected
        ## The focus call is to appease Chrome
        self.selenium.focus('id=id_security_form_json_api_url')
        self.selenium.click('id=id_security_form_json_api_url')

        # our 'caret' plugin appears to have a problem getting the selection
        # range for fields that are not editable, such as the json api url.
        # Consequently, we have to check the selection by copying this
        # text, and checking the clipboard content.
        with self.key_down(key_codes.CTRL):
            self.human_key_press(key_codes.LETTER_C)

        def get_clipboard_text():
            OpenClipboard()
            text = GetClipboardData(win32con.CF_TEXT)
            CloseClipboard()
            return text

        self.wait_for(
            lambda: get_clipboard_text() == api_url,
            lambda: 'bad clipboard text, was: %s' % (get_clipboard_text(),)
        )

        # * nothing appears outside the JSON API dialog box yet though.
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        # * He ignores all of the key stuff, presses Cancel
        self.selenium.click('id=id_security_form_cancel_button')

        # * He notices that the form disappears and that the icon still indicates that the JSON API is disabled
        self.wait_for_element_visibility('id=id_security_form', False)
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API disabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        # but he just tries accessing the JSON URL without a key again
        # * He gets 403 again.
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url)
        self.assertEquals(mngr.exception.code, 403)

        # * and he also gets 403 when he uses the API Key that was displayed
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url, urlencode({'api_key': api_key}))
        self.assertEquals(mngr.exception.code, 403)

        # * He half-realises what the problem is, opens the dialog again, checks the box, and presses OK
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.assertEquals(self.selenium.get_value('id=id_security_form_json_enabled_checkbox'), 'off')
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.assertTrue(self.is_element_enabled('id_security_form_json_api_key'))
        self.assertTrue(self.is_element_enabled('id_security_form_json_api_url'))
        api_url = self.selenium.get_value('css=#id_security_form_json_api_url')
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)

        #* He now sees the toolbar indicates that the JSON API is enabled for this sheet
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        # * Not trusting the memory of his browser, he opens the dialog again
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.assertEquals(self.selenium.get_value('id=id_security_form_json_enabled_checkbox'), 'on')

        # * and immediately presses Cancel
        self.selenium.click('id=id_security_form_cancel_button')

        # * He is surprised and delighted to see that his sheet is still JSON-enabled
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        expected_url = "%s%s?api_key=%s" % (
            self.selenium.browserURL[:-1],
            urlparse(Url.api_url(self.get_my_username(), sheet_id)).path,
            api_key
        )
        self.assertEquals(api_url, expected_url)

        # .. despite this helpful link, he tries again with the wrong API key
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url, urlencode({'api_key': 'abcd1234-123dfe'}))
        # * He gets a 403
        self.assertEquals(mngr.exception.code, 403)


        # * Frustrated, he tries again with the right API key.
        response = urlopen(base_json_url, urlencode({'api_key': api_key}))

        # * He gets the data he expected.
        json_data = json.load(response)
        self.assertEquals(json_data['1']['1'], 5)

        # * He changes the API key in the JSON API dialog.
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        old_api_url = self.selenium.get_value('css=#id_security_form_json_api_url')
        self.selenium.type('id=id_security_form_json_api_key', 'some_new_api_ke')
        self.selenium.focus('id=id_security_form_json_api_key')

        # He sees that the api url is updated with every keystroke
        self.human_key_press(key_codes.END) # Move IE insert point to the end
        self.human_key_press(key_codes.LETTER_Y)

        self.assertEquals(
            self.selenium.get_value('css=#id_security_form_json_api_url'),
            old_api_url.replace(api_key, 'some_new_api_key')
        )
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)

        # * He tries again, using the old key
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url, urlencode({'api_key': api_key}))
        # * He gets a 403
        self.assertEquals(mngr.exception.code, 403)

        # * He tries using the right key.
        response = urlopen(base_json_url, urlencode({'api_key': 'some_new_api_key'}))

        # * It works.
        json_data = json.load(response)
        self.assertEquals(json_data['1']['1'], 5)

        # * He refreshes the sheet page
        self.refresh_sheet_page()

        # * and notes that his setting has been remembered by the server
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.assertEquals(self.selenium.get_value('id=id_security_form_json_enabled_checkbox'), 'on')

        # * He makes the sheet private again.
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)

        # * He tries with the key that worked last time.
        with self.assertRaises(HTTPError) as mngr:
            urlopen(base_json_url, urlencode({'api_key': 'some_new_api_key'}))
        # * He gets a 403
        self.assertEquals(mngr.exception.code, 403)


    def test_link_to_documentation_in_dialog(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He goes to the security dialog.
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)

        # * He is puzzled by the JSON API option, so he clicks on its help link
        # * The link goes into a new window
        ## Selenium gets Very Unhappy with target=_blank, so we just check that it's there and
        ## then remove it so as not to frighten the poor thing.
        self.assertEquals(
            self.selenium.get_attribute('id=id_security_form_json_help@target'),
            "_blank"
        )
        self.selenium.get_eval("window.$('#id_security_form_json_help').removeAttr('target')")
        self.selenium.click("id=id_security_form_json_help")
        self.selenium.wait_for_page_to_load(PAGE_LOAD_TIMEOUT)

        # containing a documentation page that explains it all
        title = self.browser.title
        self.assertTrue(title.startswith('The JSON API'))
        self.assertTrue(title.endswith('documentation'))


    def test_run_worksheet_with_json_disabled_sheets(self):
        # * Harold logs in to Dirigible and creates a new sheet, with some stuff in it
        self.login_and_create_new_sheet()
        rws_sheet_url = self.browser.current_url
        self.enter_cell_text(1, 1, '5')

        # * He creates another new sheet
        self.create_new_sheet()
        base_json_url = urljoin(self.browser.current_url, 'v0.1/json/')

        # * and enables JSON API access
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.selenium.type('id=id_security_form_json_api_key', self.get_my_username())
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)

        # * He enters a formula that uses run_worksheet on the first sheet
        self.enter_cell_text(1, 1, "=run_worksheet('%s')[1, 1].value" % (rws_sheet_url,))
        self.wait_for_cell_value(1, 1, '5')

        # * and tries to access it via the JSON API
        try:
            response = urlopen(base_json_url, urlencode({'api_key': self.get_my_username()}))
        except HTTPError, err:
            self.fail(err.read())

        # * It works.
        json_data = json.load(response)
        self.assertEquals(json_data['1']['1'], 5)


    def test_json_api_auth_reports_server_error(self):
        # * Harold logs in to Dirigible and creates a new sheet, with some stuff in it
        self.login_and_create_new_sheet()

        # * and enables JSON API access
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)
        self.selenium.click('id=id_security_form_json_enabled_checkbox')
        self.selenium.type('id=id_security_form_json_api_key', self.get_my_username())

        # Something goes wrong with the Dirigible server
        old_set_security_settings_url = self.selenium.get_eval("window.urls.setSecuritySettings")
        self.selenium.get_eval("window.urls.setSecuritySettings = 'blergh'")

        # Blissfully unaware of this, Harold clicks OK.
        self.selenium.click('id=id_security_form_ok_button')

        # The dialog remains, and an error div appears to tell him that something is wrong.
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', True)

        # He waits for a moment, and the server magically fixes itself.
        self.selenium.get_eval("window.urls.setSecuritySettings = '%s'" % (old_set_security_settings_url,))

        # He tries again, and the dialog disappears.
        self.selenium.click('id=id_security_form_ok_button')
        self.wait_for_element_visibility('id=id_security_form', False)

        # The sheet page confirms that his changes are there.
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )

        # He pops up the dialog and is pleased to see that there is no error message there.
        self.selenium.click('id=id_security_button')
        self.wait_for_element_visibility('id=id_security_form', True)
        self.wait_for_element_visibility('id=id_security_form_save_error', False)

        # He refreshes the page and confirms from the toolbar buttons that his changes really were saved.
        self.refresh_sheet_page()
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@title')
        )
        self.assertTrue(
            'JSON API enabled' in
            self.selenium.get_attribute('css=#id_security_button@alt')
        )


================================================
FILE: dirigible/fts/tests/test_2571_DocumentationAndBlogLinks.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from urlparse import urljoin


from functionaltest import FunctionalTest, Url


class Test_2571_Documentation(FunctionalTest):

    def get_link_href(self, link_id):
        url = self.selenium.get_attribute("id=%s@href" % (link_id,))
        return urljoin(Url.ROOT, url)


    def test_main_documentation_page_exists(self):
        # * Harold goes to the Dirigible front page.
        self.go_to_url(Url.ROOT)

        # * He sees that there is a link to a blog, and notes down where it goes to.
        blog_url = self.get_link_href("id_blog_link")

        # * He goes to url http://IP/documentation
        self.go_to_url(Url.DOCUMENTATION)

        # * He gets back a page, not a 404, the title of which which contains the words 'Dirigible' and 'documentation'
        title = self.browser.title.lower()
        self.assertTrue("documentation" in title)
        self.assertTrue("dirigible" in title)

        # * He logs in and creates a sheet, and notices that there is a link to the
        #   same documentation page.
        self.login_and_create_new_sheet()
        self.assertEquals(self.get_link_href("id_help_link"), Url.DOCUMENTATION)

        # ...and that there is also a link to the same blog.
        self.assertEquals(self.get_link_href("id_blog_link"), blog_url)

        # * He follows the link to his dashboard.
        self.click_link('id_account_link')

        # * He sees the same help and blog links there, and confirms they go to the same places.
        self.assertEquals(self.get_link_href("id_help_link"), Url.DOCUMENTATION)
        self.assertEquals(self.get_link_href("id_blog_link"), blog_url)

================================================
FILE: dirigible/fts/tests/test_2577_SaveColumnWidths.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from textwrap import dedent
import time

from functionaltest import FunctionalTest, PAGE_LOAD_TIMEOUT


DELTA = 30

class Test_2537_save_column_widths(FunctionalTest):


    def get_column_header_locator(self, column_name):
        return 'css=div[title=%s]' % (column_name,)


    def get_column_resize_handle_locator(self, column_name):
        return "%s div.slick-resizable-handle" % (self.get_column_header_locator(column_name),)


    def get_column_width(self, column_name):
        return self.selenium.get_element_width(self.get_column_header_locator(column_name))


    def wait_for_column_width(self, column_name, width):
        self.wait_for(
            lambda: self.get_column_width(column_name) == width,
            lambda: 'column %s width to become %s (was %s)' % (column_name, width, self.get_column_width(column_name))
        )


    def resize_column(self, column_name, width_delta):
        orig_column_width = self.get_column_width(column_name)

        self.selenium.drag_and_drop(
            self.get_column_resize_handle_locator(column_name),
            '%d,+0' % (width_delta,)
        )

        self.wait_for_column_width(column_name, orig_column_width + width_delta)



    def test_save_em(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # He resizes a column
        self.resize_column('B', 30)

        new_size = self.get_column_width('B')

        # * He refreshes the page
        self.refresh_sheet_page()

        # * the resized column is still enbiggenened
        self.wait_for_grid_to_appear()
        self.wait_for_column_width('B', new_size)



    def test_changing_column_widths_does_not_interrupt_recalc_but_does_save_widths(self):
        # * Harold logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * He sets up a long recalc
        self.enter_cell_text(1, 1, '1')
        self.append_usercode(dedent('''
        worksheet[1, 1].value += 1
        import time
        time.sleep(30)
        '''))

        # * After it's been running for a while, but before it is finished,
        #   he plays with the column widths.  (Waiting for this makes sure that
        #   we can distinguish between the completion of the first recalc (which
        #   should happen within the time the usercode takes to execute plus or
        #   minus a bit) and the completion of a second recalc that was somehow
        #   triggered by broken column-resize code; resizing columns should
        #   *not* trigger a recalc.)
        time.sleep(20)
        self.resize_column('B', 30)
        col_b_width = self.get_column_width('B')
        self.resize_column('C', -10)
        col_c_width = self.get_column_width('C')

        # * and notes that the recalc completes normally -- ie.
        #   that when it completed it did not see the updated
        #   column widths and think that the sheet had changed
        #   underneath it, and thus abort and send back an error
        #   -- and also that it completes within <usercode-time>
        #   from the initial setting of the usercode, not within
        #   a larger amount of time (which would imply that setting
        #   column widths triggered a recalc.
        self.wait_for_cell_value(1, 1, '2', timeout_seconds=15)

        # * He then refreshes the page to make sure that the recalc
        #   that just finished copied the new column widths to the DB.
        self.refresh_sheet_page()
        self.wait_for_grid_to_appear()
        self.wait_for_column_width('B', col_b_width)
        self.wait_for_column_width('C', col_c_width)


================================================
FILE: dirigible/fts/tests/test_2581_FormulaBar.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest, snapshot_on_error
import key_codes


class Test_2581_FormulaBar(FunctionalTest):

    def wait_for_formula_bar_enabled(self):
        self.wait_for(
            self.is_formula_bar_enabled,
            lambda: 'formula bar to enable',
        )

    def wait_for_formula_bar_disabled(self):
        self.wait_for(
            lambda: not self.is_formula_bar_enabled(),
            lambda: 'formula bar to disable',
        )

    def test_formula_bar(self):
        # Harold lacks the mental egg-juggling capacity of a Real Programmer,
        # and wants to be reminded of relevant state as he examines his
        # spreadsheet.

        # * He logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He observes that there is a single-line text box above the grid.
        bar_bounds = self.get_element_bounds(self.get_formula_bar_locator())

        grid_locator = "id=id_grid"
        grid_bounds = self.get_element_bounds(grid_locator)

        self.assertTrue(
            abs(bar_bounds.left - grid_bounds.left) < 50,
            "Grid and formula bar not roughly horizontally aligned"
        )
        self.assertTrue(
            abs(bar_bounds.width - grid_bounds.width) < 100,
            "Grid and formula bar not roughly the same width"
        )
        self.assertTrue(
            bar_bounds.top + bar_bounds.height < grid_bounds.top,
            "Formula bar not above grid"
        )

        # * He notes that cell A1 is active, and he can edit the formula bar,
        #   which is empty
        ## NB click doesn't work here -- it's for links and buttons only.
        ## Which makes it strange that it works with cells!
        self.wait_for_cell_to_become_active(1, 1)
        self.wait_for_formula_bar_enabled()
        self.click_formula_bar()
        self.assertTrue(
            self.is_element_focused('id=%s' % (self.get_formula_bar_id(),)))
        self.wait_for_formula_bar_contents("")

        # * As he starts to type "456", he observes that the cell editor
        #   updates with each keystroke.
        self.human_key_press(key_codes.NUMBER_4)
        # workaround for defect T2708
        #self.wait_for_cell_editor_content("4")

        self.human_key_press(key_codes.NUMBER_5)
        self.wait_for_cell_editor_content("45")

        self.human_key_press(key_codes.NUMBER_6)
        self.wait_for_cell_editor_content("456")

        # * He then edits cell A2
        self.open_cell_for_editing(1, 2)
        self.wait_for_cell_to_enter_edit_mode(1, 2)

        # and notes that the formula bar becomes empty
        self.wait_for_formula_bar_contents("")

        # while cell A1 still contains "456".
        self.wait_for_cell_value(1, 1, "456")

        # * He types "123"; as he does so, the contents of the formula bar
        #   update with each keystroke.
        self.human_key_press(key_codes.NUMBER_1)
        self.wait_for_formula_bar_contents("1")

        self.human_key_press(key_codes.NUMBER_2)
        self.wait_for_formula_bar_contents("12")

        self.human_key_press(key_codes.NUMBER_3)
        self.wait_for_formula_bar_contents("123")

        # * He edits cell A1, and notes that both the cell and the formula bar
        #   read "456".
        self.open_cell_for_editing(1, 1)
        self.wait_for_cell_editor_content("456")
        self.wait_for_formula_bar_contents("456")

        # * Harold edits A3, and enters "78".
        self.open_cell_for_editing(1, 3)
        self.human_key_press(key_codes.NUMBER_7)
        self.human_key_press(key_codes.NUMBER_8)

        #   The formula bar shows 78.
        self.wait_for_formula_bar_contents("78")

        # * He clicks in the formula bar, hits the "end" key, and enters "90".
        self.click_formula_bar()
        self.human_key_press(key_codes.END)
        self.human_key_press(key_codes.NUMBER_9)
        self.human_key_press(key_codes.NUMBER_0)

        #   The cell editor and the formula bar both show 7890.
        self.wait_for_cell_editor_content("7890")
        self.assert_formula_bar_contains("7890")

        # * Harold clicks on A4,
        self.click_on_cell(1, 4)

        #   and then wonders whether he can commit changes from the formula bar
        #   without click to a cell, so he clicks on the formula bar,
        self.click_formula_bar()

        #  types "321<ENTER>".
        self.human_key_press(key_codes.NUMBER_3)
        self.human_key_press(key_codes.NUMBER_2)
        self.human_key_press(key_codes.NUMBER_1)
        self.human_key_press(key_codes.ENTER)

        #    and is delighted to see the cell update.
        self.wait_for_cell_value(1, 4, "321")


    @snapshot_on_error
    def test_formula_bar_remains_enabled_at_all_times(self):

        # Harry logs in and creates a new sheet.
        self.login_and_create_new_sheet()

        # * the formula bar is enabled because a cell has focus
        self.wait_for_formula_bar_enabled()
        self.wait_for_cell_to_become_active(1, 1)

        # * he clicks in the output pane
        #  the formula bar remains enabled
        self.selenium.click('id=id_console')
        self.wait_for_formula_bar_enabled()

        # * he clicks in the usercode
        #  the formula bar remains enabled
        self.selenium.get_eval('window.editor.focus()')
        self.wait_for_formula_bar_enabled()

        # * he clicks in the sheet title
        #  the formula bar remains enabled
        self.selenium.click('id=id_sheet_name')
        self.wait_for_formula_bar_enabled()

        # He presses escape to cancel the sheet title edit
        self.human_key_press(key_codes.ESCAPE)

        #  * He clicks in the formula bar
        self.click_formula_bar()

        #  and types "321<ENTER>".
        self.human_key_press(key_codes.NUMBER_3)
        self.human_key_press(key_codes.NUMBER_2)
        self.human_key_press(key_codes.NUMBER_1)
        self.human_key_press(key_codes.ENTER)

        # and is delighted to see cell A1 update.
        self.wait_for_cell_value(1, 1, "321")


================================================
FILE: dirigible/fts/tests/test_2582_ReferencingEmptyCell.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2582_ReferencingEmptyCell(FunctionalTest):

    def test_referencing_empty_cell(self):
        # Harold logs in and creates a new sheet.
        self.login_and_create_new_sheet()

        # He enters "=A1" into B1
        self.enter_cell_text(2, 1, '=A1')

        # He sees that B1 is in its "I have no value but my formula is '=A1'" state.
        self.wait_for_cell_shown_formula(2, 1, '=A1')

        # Cell A1 is blank.
        self.wait_for_cell_value(1, 1, '')
        self.wait_for_spinner_to_stop()

        # There is nothing in the error console.
        self.assertTrue(
            self.get_console_content().startswith('Took'),
            "Unexpected error console content:\n%r" % (self.get_console_content(),)
        )

        # He adds code to set the value of C1 to the end of the user code.
        self.append_usercode("worksheet[3, 1].value = 23")

        # He notes that it is being executed.
        self.wait_for_cell_value(3, 1, '23')


================================================
FILE: dirigible/fts/tests/test_2592_Cut_Copy_Paste_Within_Dirigible.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from __future__ import with_statement

from textwrap import dedent

from functionaltest import FunctionalTest, Url
import key_codes

class Test_2592_Cut_Copy_Paste_within_Dirigible(FunctionalTest):

    def wait_for_only_active_cell_selected(self):
        def is_only_active_cell_selected():
            return self.selenium.get_eval("""
                (function() {
                    var selectedCells = window.$('.selected');
                    if (selectedCells.length !== 1) {
                        return false;
                    }

                    return selectedCells[0] === window.$('.active')[0];
                })()
            """) == 'true'

        self.wait_for(
            is_only_active_cell_selected,
            lambda: "Only active cell to be selected"
        )


    def test_block_selection(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # He tries to select a range by dragging from B2 to C5
        self.mouse_drag((2, 3), (3, 6))
        self.assert_current_selection((2, 3), (3, 6))

        # he clicks outside the range and sees his selection disappear
        self.click_on_cell(7, 7)
        self.wait_for_only_active_cell_selected()

        # He then uses shift + arrow keys

        # selenium needs a little jquery-kick to get shift-key-down working
        self.selenium.get_eval("window.$('div.grid-canvas').trigger({type:'keydown', which: 16});")

        self.human_key_press(key_codes.LEFT)
        self.assert_current_selection((6, 7), (7, 7))
        self.human_key_press(key_codes.LEFT)
        self.assert_current_selection((5, 7), (7, 7))
        self.human_key_press(key_codes.LEFT)
        self.assert_current_selection((4, 7), (7, 7))
        self.human_key_press(key_codes.UP)
        self.assert_current_selection((4, 6), (7, 7))
        self.human_key_press(key_codes.UP)
        self.assert_current_selection((4, 5), (7, 7))
        self.human_key_press(key_codes.UP)
        self.assert_current_selection((4, 4), (7, 7))
        self.selenium.get_eval("window.$('div.grid-canvas').trigger({type:'keyup', which: 16});")

        # he clicks *inside* the range and sees his selection disappear
        self.click_on_cell(5, 5)
        self.wait_for_only_active_cell_selected()

        # * He finally settles on shift + mouse click as his favourite
        #   method for selecting a range
        self.click_on_cell(2, 3)
        with self.key_down(key_codes.SHIFT):
            self.click_on_cell(8, 7)
        self.assert_current_selection((2, 3), (8, 7))

        # he checks you cannot select the header areas
        self.click_on_cell(1, 1)
        self.selenium.get_eval("window.$('div.grid-canvas').trigger({type:'keydown', which: 16});")
        self.human_key_press(key_codes.LEFT)
        self.assert_current_selection((1, 1), (1, 1))
        self.human_key_press(key_codes.UP)
        self.assert_current_selection((1, 1), (1, 1))


    def assert_copy_and_paste(
        self, operation, source_sheet,
        dest_sheet=None, dest_location=None, to_set='formula'
    ):
        if dest_sheet is None:
            dest_sheet = source_sheet

        # he populates some cells using usercode (because the test runs faster)
        orig_usercode = self.get_usercode()
        self.prepend_usercode(dedent('''
            for row in range(3, 6):
                for col in 'BC':
                    worksheet[col, row].%s = '%%s%%d' %% (col, row)
        ''' % (to_set,)
        ))
        self.wait_for_cell_value(2, 3, 'B3')

        if to_set == 'formula':
            self.enter_usercode(orig_usercode)
            self.wait_for_spinner_to_stop()

        # he copies (or cuts) a region from one place
        operation((2, 3), (3, 5))

        # If he's cutting, it disappears
        if operation == self.cut_range:
            self.wait_for_cell_value(2, 3, '')
            self.wait_for_cell_value(3, 3, '')
            self.wait_for_cell_value(2, 4, '')
            self.wait_for_cell_value(3, 4, '')
            self.wait_for_cell_value(2, 5, '')
            self.wait_for_cell_value(3, 5, '')

        # ...and pastes it elsewhere
        if dest_sheet != source_sheet:
            self.go_to_url( Url.sheet_page(self.get_my_username(), dest_sheet) )
            self.wait_for_grid_to_appear()

        self.paste_range(dest_location)

        # the destination is populated
        c, r = dest_location
        self.wait_for_cell_value(  c,   r, 'B3')
        self.wait_for_cell_value(1+c,   r, 'C3')
        self.wait_for_cell_value(  c, 1+r, 'B4')
        self.wait_for_cell_value(1+c, 1+r, 'C4')
        self.wait_for_cell_value(  c, 2+r, 'B5')
        self.wait_for_cell_value(1+c, 2+r, 'C5')


    def test_copy_and_paste_southeast(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # he does a copy and paste, and sees the destination cells update
        self.assert_copy_and_paste(self.copy_range, sheet_id, dest_location=(3, 4))

        # the non-overlapped source cells are unchanged
        self.wait_for_cell_value(2, 3, 'B3')
        self.wait_for_cell_value(2, 4, 'B4')
        self.wait_for_cell_value(2, 5, 'B5')
        self.wait_for_cell_value(3, 3, 'C3')


    def test_copy_and_paste_northwest(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        self.assert_copy_and_paste(self.copy_range, sheet_id, dest_location=(1, 2))

        # the non-overlapped source cells are unchanged
        self.wait_for_cell_value(2, 5, 'B5')
        self.wait_for_cell_value(3, 3, 'C3')
        self.wait_for_cell_value(3, 4, 'C4')
        self.wait_for_cell_value(3, 5, 'C5')


    def test_copy_and_paste_to_new_sheet(self):
        # * Harold logs in to Dirigible and creates a new sheet
        dest_sheet = self.login_and_create_new_sheet()
        source_sheet = self.create_new_sheet()

        self.assert_copy_and_paste(
            self.copy_range, source_sheet, dest_sheet, dest_location=(3, 4))

        # the cells in the original sheet are all still there
        self.go_to_url( Url.sheet_page(self.get_my_username(), source_sheet) )
        self.wait_for_grid_to_appear()
        self.wait_for_cell_value(2, 3, 'B3')
        self.wait_for_cell_value(2, 4, 'B4')
        self.wait_for_cell_value(2, 5, 'B5')
        self.wait_for_cell_value(3, 3, 'C3')
        self.wait_for_cell_value(3, 4, 'C4')
        self.wait_for_cell_value(3, 5, 'C5')


    def test_cut_and_paste_southeast(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        self.assert_copy_and_paste(self.cut_range, sheet_id, dest_location=(3, 4))

        # the source cells that weren't pasted over are cleared
        self.wait_for_cell_value(2, 3, '')
        self.wait_for_cell_value(3, 3, '')
        self.wait_for_cell_value(2, 4, '')
        self.wait_for_cell_value(2, 5, '')


    def test_cut_and_paste_northwest(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        self.assert_copy_and_paste(self.cut_range, sheet_id, dest_location=(1, 2))

        # the source cells that weren't pasted over are cleared
        self.wait_for_cell_value(2, 5, '')
        self.wait_for_cell_value(3, 3, '')
        self.wait_for_cell_value(3, 4, '')
        self.wait_for_cell_value(3, 5, '')


    def test_cut_and_paste_to_new_sheet(self):
        # * Harold logs in to Dirigible and creates two new sheets
        dest_sheet = self.login_and_create_new_sheet()
        source_sheet = self.create_new_sheet()

        # He cuts stuff from one to the other
        self.assert_copy_and_paste(
            self.cut_range, source_sheet, dest_sheet, dest_location=(3, 4))


    def test_multiple_pastes_after_copy(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # He copies some stuff towards the southeast
        self.assert_copy_and_paste(self.copy_range, sheet_id, dest_location=(3, 4))

        # the non-overlapped source cells are unchanged
        self.wait_for_cell_value(2, 3, 'B3')
        self.wait_for_cell_value(2, 4, 'B4')
        self.wait_for_cell_value(2, 5, 'B5')
        self.wait_for_cell_value(3, 3, 'C3')

        # he then tries pasting again, even further south east.
        c, r = 10, 20
        self.paste_range((c, r))

        # the destination is populated
        self.wait_for_cell_value(  c,   r, 'B3')
        self.wait_for_cell_value(1+c,   r, 'C3')
        self.wait_for_cell_value(  c, 1+r, 'B4')
        self.wait_for_cell_value(1+c, 1+r, 'C4')
        self.wait_for_cell_value(  c, 2+r, 'B5')
        self.wait_for_cell_value(1+c, 2+r, 'C5')

        # the source and original paste are unchanged
        self.wait_for_cell_value(2, 3, 'B3')
        self.wait_for_cell_value(3, 4, 'B3')

        # he sets a cell formula
        self.enter_cell_text(1, 1, "hope this doesn't kill the clipboard!")
        self.wait_for_cell_value(1, 1, "hope this doesn't kill the clipboard!")

        # he tries to paste again slightly southeast
        c, r = 11, 21
        self.paste_range((c, r))

        # and is pleased to see the destination populated
        self.wait_for_cell_value(  c,   r, 'B3')
        self.wait_for_cell_value(1+c,   r, 'C3')
        self.wait_for_cell_value(  c, 1+r, 'B4')
        self.wait_for_cell_value(1+c, 1+r, 'C4')
        self.wait_for_cell_value(  c, 2+r, 'B5')
        self.wait_for_cell_value(1+c, 2+r, 'C5')

        # he double checks the source and earlier pastes are unchanged
        self.wait_for_cell_value(2, 3, 'B3')
        self.wait_for_cell_value(3, 4, 'B3')
        self.wait_for_cell_value(10, 20, 'B3')


    def test_multiple_pastes_after_cut(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        #  He cuts & pastes some stuff towards the southeast
        self.assert_copy_and_paste(self.cut_range, sheet_id, dest_location=(3, 4))

        # he hits paste again, further down
        c, r = 10, 20
        self.paste_range((c, r))

        # the destination is populated
        self.wait_for_cell_value(  c,   r, 'B3')
        self.wait_for_cell_value(1+c,   r, 'C3')
        self.wait_for_cell_value(  c, 1+r, 'B4')
        self.wait_for_cell_value(1+c, 1+r, 'C4')
        self.wait_for_cell_value(  c, 2+r, 'B5')
        self.wait_for_cell_value(1+c, 2+r, 'C5')

        # he now sets a cell formula
        self.enter_cell_text(1, 1, "hope this doesn't kill the clipboard!")
        self.wait_for_cell_value(1, 1, "hope this doesn't kill the clipboard!")

        # he tries to paste again slightly southeast
        c, r = 11, 21
        self.paste_range((c, r))

        # and is pleased to see the destination populated
        self.wait_for_cell_value(  c,   r, 'B3')
        self.wait_for_cell_value(1+c,   r, 'C3')
        self.wait_for_cell_value(  c, 1+r, 'B4')
        self.wait_for_cell_value(1+c, 1+r, 'C4')
        self.wait_for_cell_value(  c, 2+r, 'B5')
        self.wait_for_cell_value(1+c, 2+r, 'C5')

        # he double checks the original source is still empty
        self.wait_for_cell_value(2, 3, '')

        #and earlier pastes are unchanged
        self.wait_for_cell_value(3, 4, 'B3')
        self.wait_for_cell_value(10, 20, 'B3')


    def test_values_wo_formulae_are_promoted(self):
        # * Harold logs in to Dirigible and creates a new sheet
        sheet_id = self.login_and_create_new_sheet()

        # he sets up a range with just values, no formulae, and checks they get
        # copied
        self.assert_copy_and_paste(self.copy_range, sheet_id,
            dest_location=(3, 4), to_set='value')


    def test_target_range_is_cleared_before_paste(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters some values into the grid
        #   making sure that there are some gaps
        for row in range(1, 6, 2):
            self.enter_cell_text(1, row, 'filled')
        self.copy_range((1, 1), (1, 6))

        # * He copies a section of the values over another section
        #   and notes that the gaps in the source range are replicated in the target
        self.paste_range((1, 2))
        self.wait_for_cell_value(1, 3, '')


    def test_mouse_drags_dont_lose_current_cell_edits(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        self.click_on_cell(1, 1)
        self.human_key_press(key_codes.NUMBER_1)
        self.human_key_press(key_codes.NUMBER_2)

        self.mouse_drag((2, 3), (3, 6))


================================================
FILE: dirigible/fts/tests/test_2595_Spinner.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2595_Throbber(FunctionalTest):

    def test_spinner_appears_during_recalcs(self):
        # * Harold likes to know when dirigible is working hard on his calculations

        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * When the grid has appeared, the spinner might be visible, but it disappears
        #   rapidly as the initial empty recalc completes.
        self.wait_for_spinner_to_stop()

        # * and enters some hard-working user-code
        self.append_usercode('import time\ntime.sleep(20)\nworksheet[1,1].value="ready"')

        # * He spots the spinner on the page
        self.wait_for(self.is_spinner_visible,
                      lambda : 'spinner not present',
                      timeout_seconds = 5)

        # * When the recalc is done, he sees the spinner go away
        self.wait_for_cell_value(1, 1, 'ready', timeout_seconds=25)

        self.assertTrue(self.is_element_present('css=#id_spinner_image.hidden'))


================================================
FILE: dirigible/fts/tests/test_2597_CapRecalcTime.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#


from functionaltest import FunctionalTest


class Test_2597_CapRecalcTime(FunctionalTest):

    def test_recalcs_get_stopped(self):
        # * Harold doesn't want to waste money on recalculations where he created an
        #   infinite loop. Dirigible helpfully kills any recalculations that are
        #   taking too long. The default (set in the database per sheet) is 60sec.

        # * He logs in and creates a new sheet
        self.login_and_create_new_sheet()

        # * and enters some ill-advised user-code
        self.append_usercode('while True: pass\n\n#some stuff')
        fn_call_line = self.get_usercode().split('\n').index('while True: pass')

        # * He notes that after a minute, there is a message in the console
        #   telling him that his recalculation timed out.
        self.wait_for_console_content(
            'TimeoutException: \n    User code line 10',
            timeout_seconds=59
        )



================================================
FILE: dirigible/fts/tests/test_2601_UndefinedShouldBeAvailableToUsercode.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from functionaltest import FunctionalTest


class Test_2601_UndefinedShouldBeAvailableToUsercode(FunctionalTest):

    def test_use_undefined(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He uses undefined in A1.
        self.enter_cell_text(1, 1, '=A2==undefined')
        self.wait_for_cell_value(1, 1, 'True')
        self.assert_cell_has_no_error(1, 1)

        # * he uses undefined in usercode
        self.append_usercode('worksheet[1,3].value = worksheet[1,4].value==undefined')
        self.wait_for_cell_value(1, 3, 'True')
        self.assertTrue(self.get_console_content().startswith('Took'))

        # hooray!



================================================
FILE: dirigible/fts/tests/test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from textwrap import dedent

from functionaltest import FunctionalTest, Url


class Test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete(FunctionalTest):

    def test_sheet_page_displays_fast(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()
        sheet_page = self.browser.current_url

        # * He sets it up so that it takes 30 seconds to recalc.
        self.enter_cell_text(1, 2, '=123')
        self.enter_usercode(dedent("""
            import time
            time.sleep(30.0)
            load_constants(worksheet)
            evaluate_formulae(worksheet)
            worksheet[2,2].value = 'usercode completed'
        """))
        self.wait_for_cell_value(2, 2, 'usercode completed', timeout_seconds=35)
        self.wait_for_cell_value(1, 2, '123')

        # * He navigates to a different page.
        self.go_to_url(Url.ROOT)

        # * He goes back to the sheet page.
        self.go_to_url(sheet_page)

        # * He notes that the grid takes less than 10 seconds to appear.
        self.wait_for_grid_to_appear(timeout_seconds=10)

        # * Once the grid is loaded, but before the recalc has completed, it
        #   displays the results of his formulae and usercode-only values
        #   even before the recalc is complete
        self.wait_for_cell_value(1, 2, '123', timeout_seconds=35)
        self.wait_for_cell_value(2, 2, 'usercode completed')


================================================
FILE: dirigible/fts/tests/test_2603_WorksheetsMayOnlyContainCells.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#
from textwrap import dedent

from functionaltest import FunctionalTest


class test_2603_WorksheetsMayOnlyContainCells(FunctionalTest):

    def test_setting_worksheet_location_to_non_cell_raises(self):
        # * Harold logs in to Dirigible and creates a new sheet
        self.login_and_create_new_sheet()

        # * He enters usercode which sets a worksheet location to a non-cell
        self.append_usercode('worksheet[1,1] = 123')
        error_line = len(self.get_usercode().split('\n'))
        expected = dedent('''
            TypeError: Worksheet locations must be Cell objects
                User code line %d''' % (error_line,))[1:]
        self.wait_for_console_content(expected)

        # hooray!



================================================
FILE: dirigible/fts/tests/test_2616_RootPageIsDashboard.py
================================================
# Copyright (c) 2010 Resolver Systems Ltd.
# All Rights Reserved
#

from urlparse import urlparse, urlunparse

from functionaltest im
Download .txt
gitextract_vy1u92c1/

├── .gitignore
├── LICENSE.md
├── README.md
├── dirigible/
│   ├── .gitignore
│   ├── dirigible/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── test_utils.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── featured_sheet/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── featured_sheets.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_models.py
│   │   └── views.py
│   ├── feedback/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── fts/
│   │   ├── __init__.py
│   │   ├── screendumps/
│   │   │   └── placeholder
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── functionaltest.py
│   │       ├── test_2521_CodeEditor.py
│   │       ├── test_2525_LoginLogout.py
│   │       ├── test_2528_CreateEditSheet.py
│   │       ├── test_2529_HighlightErrorsInCells.py
│   │       ├── test_2531_DifficultStuffInCells.py
│   │       ├── test_2532_LambdasInCells.py
│   │       ├── test_2533_Numpy.py
│   │       ├── test_2534_JsonWorksheets.py
│   │       ├── test_2535_RunWorksheetSerial.py
│   │       ├── test_2536_ParallelFormulaExecution.py
│   │       ├── test_2537_ErrorsInConsole.py
│   │       ├── test_2538_ShowStdoutInConsole.py
│   │       ├── test_2540_FrontPage.py
│   │       ├── test_2544_403_404_and_500_pages.py
│   │       ├── test_2545_PageResizeBehaviour.py
│   │       ├── test_2546_ListSheetsOnDashboard.py
│   │       ├── test_2547_EnterDataQuickly.py
│   │       ├── test_2548_UserCode.py
│   │       ├── test_2549_InterruptedRecalculations.py
│   │       ├── test_2550_EditableSheetName.py
│   │       ├── test_2554_SlicingInFormulae.py
│   │       ├── test_2556_BrokenUserCode.py
│   │       ├── test_2557_ClickAwaySavesUsercode.py
│   │       ├── test_2558_MoreCellsByDefault.py
│   │       ├── test_2559_FitEditorToCells.py
│   │       ├── test_2562_ErrorInCellShouldBeClearedByConstants.py
│   │       ├── test_2565_JSONAPIAuth.py
│   │       ├── test_2571_DocumentationAndBlogLinks.py
│   │       ├── test_2577_SaveColumnWidths.py
│   │       ├── test_2581_FormulaBar.py
│   │       ├── test_2582_ReferencingEmptyCell.py
│   │       ├── test_2592_Cut_Copy_Paste_Within_Dirigible.py
│   │       ├── test_2595_Spinner.py
│   │       ├── test_2597_CapRecalcTime.py
│   │       ├── test_2601_UndefinedShouldBeAvailableToUsercode.py
│   │       ├── test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete.py
│   │       ├── test_2603_WorksheetsMayOnlyContainCells.py
│   │       ├── test_2616_RootPageIsDashboard.py
│   │       ├── test_2621_CanSaveSheetsWithLotsOfFormulae.py
│   │       ├── test_2622_CellRanges.py
│   │       ├── test_2631_BlogRedirect.py
│   │       ├── test_2633_CursorKeysMoveAroundGrid.py
│   │       ├── test_2635_SheetNameSelectedOnEdit.py
│   │       ├── test_2639_SciPy_and_MpMath.py
│   │       ├── test_2642_RecalcTimesInConsole.py
│   │       ├── test_2644_AdminOmniscience.py
│   │       ├── test_2650_UsercodeSandbox.py
│   │       ├── test_2651_SaveSheetNameOnBlur.py
│   │       ├── test_2652_CommitCellOnBlur.py
│   │       ├── test_2653_UsernameFocusedOnLoginPage.py
│   │       ├── test_2654_CtrlSSavesUsercode.py
│   │       ├── test_2678_GlobalStateNotShared.py
│   │       ├── test_2682_CellAccessUsingA1.py
│   │       ├── test_2685_ChangePassword.py
│   │       ├── test_2689_DontClearCellEditorWhenRecalcsHitClient.py
│   │       ├── test_2690_FocusShouldStartInGrid.py
│   │       ├── test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants.py
│   │       ├── test_2701_NameResolutionWorks.py
│   │       ├── test_2702_HttpsInChrootJail.py
│   │       ├── test_2704_OldStyleClassesInTheGrid.py
│   │       ├── test_2711_ImportExcel.py
│   │       ├── test_2712_ImportCSV.py
│   │       ├── test_2726_FormulaBarTextSelection.py
│   │       ├── test_2734_ClearCells.py
│   │       ├── test_2735_CtrlKeysArePassedOnToBrowser.py
│   │       ├── test_2741_Xlrd.py
│   │       ├── test_2749_DisallowArbitraryKeysForWorksheet.py
│   │       ├── test_2751_UsefulModules.py
│   │       ├── test_2758_LoadGridDataOnDemand.py
│   │       ├── test_2762_PythonConversion.py
│   │       ├── test_2770_ClearDependentCellErrors.py
│   │       ├── test_2774_ExportCSV.py
│   │       ├── test_2781_FormulaAndFormattedValueMustBeStrings.py
│   │       ├── test_2787_SignUp.py
│   │       ├── test_2789_ErrorConsoleHTMLEscape.py
│   │       ├── test_2795_Rewrite_Formulae_during_Cut_and_Paste.py
│   │       ├── test_2799_FillDownDuringPaste.py
│   │       ├── test_2812_CutCopyPasteInEditMode.py
│   │       ├── test_2814_PublicWorksheets.py
│   │       ├── test_2828_GridShouldNotStealFocusOnRecalc.py
│   │       ├── test_2839_CutCopyPasteButtons.py
│   │       ├── test_2844_CantMakeRowHeaderActive.py
│   │       ├── test_2848_WorksheetBounds.py
│   │       ├── test_2862_CopyAndPasteFormulaWithErrors.py
│   │       ├── test_2872_CellTooltips.py
│   │       ├── test_2873_IE_Warning.py
│   │       ├── test_2884_FeedbackForm.py
│   │       └── test_data/
│   │           ├── T2711-badly-named-png.xls
│   │           ├── T2711-import-excel.xls
│   │           ├── csv_file.csv
│   │           ├── excel_generated_csv.csv
│   │           ├── expected_csv_file.csv
│   │           ├── expected_unicode_csv.csv
│   │           ├── japanese.csv
│   │           └── public_sheet_csv_file.csv
│   ├── info_pages/
│   │   ├── __init__.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   ├── non_logged_in_front_page.html
│   │   │   ├── oss.html
│   │   │   └── video.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   └── views.py
│   ├── manage.py
│   ├── registration/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── forms.py
│   │   ├── locale/
│   │   │   ├── ar/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── bg/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── de/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── el/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── en/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── es/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── es_AR/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── fr/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── he/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── it/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── ja/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── nl/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── pl/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── pt_BR/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── ru/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── sr/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── sv/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   ├── zh_CN/
│   │   │   │   └── LC_MESSAGES/
│   │   │   │       ├── django.mo
│   │   │   │       └── django.po
│   │   │   └── zh_TW/
│   │   │       └── LC_MESSAGES/
│   │   │           ├── django.mo
│   │   │           └── django.po
│   │   ├── management/
│   │   │   ├── __init__.py
│   │   │   └── commands/
│   │   │       ├── __init__.py
│   │   │       └── cleanupregistration.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── shared/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── static/
│   │   │   ├── ace/
│   │   │   │   ├── ace-uncompressed.js
│   │   │   │   ├── ace.js
│   │   │   │   ├── cockpit-uncompressed.js
│   │   │   │   ├── cockpit.js
│   │   │   │   ├── mode-python.js
│   │   │   │   └── worker-javascript.js
│   │   │   ├── dirigible/
│   │   │   │   ├── examples/
│   │   │   │   │   └── pricelist-json-api-demo.html
│   │   │   │   ├── images/
│   │   │   │   │   └── toolbar/
│   │   │   │   │       └── api_button_disabled.pdn
│   │   │   │   ├── scripts/
│   │   │   │   │   ├── cell_editor.js
│   │   │   │   │   ├── console_view.js
│   │   │   │   │   ├── dialogs.js
│   │   │   │   │   ├── editor_commands.js
│   │   │   │   │   ├── feedback_dialog.js
│   │   │   │   │   ├── grid_commands.js
│   │   │   │   │   ├── grid_content_converter.js
│   │   │   │   │   ├── grid_interaction_handler.js
│   │   │   │   │   ├── grid_remote_model.js
│   │   │   │   │   ├── grid_view.js
│   │   │   │   │   ├── htmlescape.js
│   │   │   │   │   ├── keyboard_cellrange_selector.js
│   │   │   │   │   ├── page_commands.js
│   │   │   │   │   ├── page_interaction_handler.js
│   │   │   │   │   ├── page_view.js
│   │   │   │   │   ├── security_settings.js
│   │   │   │   │   ├── selection_model.js
│   │   │   │   │   ├── sheet_page_utils.js
│   │   │   │   │   ├── toolbar_interaction_handler.js
│   │   │   │   │   └── usercode_view.js
│   │   │   │   ├── styles/
│   │   │   │   │   ├── base.css
│   │   │   │   │   ├── coming_soon_page.css
│   │   │   │   │   ├── contact.css
│   │   │   │   │   ├── error.css
│   │   │   │   │   ├── index.css
│   │   │   │   │   ├── info_page.css
│   │   │   │   │   ├── login.css
│   │   │   │   │   ├── non_sheet_page.css
│   │   │   │   │   ├── pricing.css
│   │   │   │   │   ├── registration.css
│   │   │   │   │   ├── sheet_page.css
│   │   │   │   │   ├── user_page.css
│   │   │   │   │   └── video.css
│   │   │   │   └── tests/
│   │   │   │       ├── cell_editor_test.html
│   │   │   │       ├── console_view_test.html
│   │   │   │       ├── dialogs_test.html
│   │   │   │       ├── editor_commands_test.html
│   │   │   │       ├── feedback_dialog_test.html
│   │   │   │       ├── grid_commands_test.html
│   │   │   │       ├── grid_content_converter_test.html
│   │   │   │       ├── grid_interaction_handler_test.html
│   │   │   │       ├── grid_remote_model_test.html
│   │   │   │       ├── grid_view_test.html
│   │   │   │       ├── htmlescape_test.html
│   │   │   │       ├── jsmock.js
│   │   │   │       ├── logger.css
│   │   │   │       ├── page_commands_test.html
│   │   │   │       ├── page_interaction_handler_test.html
│   │   │   │       ├── page_view_test.html
│   │   │   │       ├── security_settings_test.html
│   │   │   │       ├── selection_model_test.html
│   │   │   │       ├── sheet_page_utils_test.html
│   │   │   │       ├── test_utils.js
│   │   │   │       ├── test_utils_test.html
│   │   │   │       ├── testlogger.css
│   │   │   │       ├── toolbar_interaction_handler_test.html
│   │   │   │       ├── usercode_view_test.html
│   │   │   │       ├── yuirunner.js
│   │   │   │       └── yuitest/
│   │   │   │           └── yuitest-combo.js
│   │   │   ├── jquery/
│   │   │   │   ├── jeip.js
│   │   │   │   ├── jquery-ui-1.8.10.custom.css
│   │   │   │   ├── jquery.ajaxq-0.0.1.js
│   │   │   │   └── jquery.cookie.js
│   │   │   ├── json/
│   │   │   │   └── json2.js
│   │   │   ├── robots.txt
│   │   │   ├── slickgrid/
│   │   │   │   ├── MIT-LICENSE.txt
│   │   │   │   ├── slick.cellrangedecorator.js
│   │   │   │   ├── slick.cellrangeselector.js
│   │   │   │   ├── slick.cellselectionmodel.js
│   │   │   │   ├── slick.core.js
│   │   │   │   ├── slick.editors.js
│   │   │   │   ├── slick.grid.css
│   │   │   │   └── slick.grid.js
│   │   │   └── splitter/
│   │   │       └── splitter.js
│   │   ├── templates/
│   │   │   ├── 403.html
│   │   │   ├── 404.html
│   │   │   ├── 500.html
│   │   │   ├── base.html
│   │   │   ├── error_page.html
│   │   │   ├── footer_links_include.html
│   │   │   ├── header_links_include.html
│   │   │   ├── info_page.html
│   │   │   └── non_sheet_page_small_logo.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_views.py
│   │   └── views.py
│   ├── sheet/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── calculate.py
│   │   ├── cell.py
│   │   ├── cell_range.py
│   │   ├── clipboard.py
│   │   ├── dependency_graph.py
│   │   ├── dirigible_datetime.py
│   │   ├── errors.py
│   │   ├── eval_constant.py
│   │   ├── forms.py
│   │   ├── formula_interpreter.py
│   │   ├── importer.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── parser/
│   │   │   ├── __init__.py
│   │   │   ├── fl_cell_range_parse_node.py
│   │   │   ├── fl_cell_reference_parse_node.py
│   │   │   ├── fl_column_reference_parse_node.py
│   │   │   ├── fl_named_column_reference_parse_node.py
│   │   │   ├── fl_named_row_reference_parse_node.py
│   │   │   ├── fl_reference_parse_node.py
│   │   │   ├── fl_row_reference_parse_node.py
│   │   │   ├── grammar.py
│   │   │   ├── parse_node.py
│   │   │   ├── parse_node_constructors.py
│   │   │   ├── parser.py
│   │   │   ├── parsetab.py
│   │   │   └── tokens.py
│   │   ├── rewrite_formula_offset_cell_references.py
│   │   ├── sheet.py
│   │   ├── templates/
│   │   │   ├── export_csv_error.html
│   │   │   ├── import_csv_error.html
│   │   │   ├── import_xls_error.html
│   │   │   └── sheet_page.html
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── parser/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_fl_cell_range_parse_node.py
│   │   │   │   ├── test_fl_cell_reference_parse_node.py
│   │   │   │   ├── test_fl_coloumn_reference_parse_node.py
│   │   │   │   ├── test_fl_named_column_reference_parse_node.py
│   │   │   │   ├── test_fl_named_row_reference_parse_node.py
│   │   │   │   ├── test_fl_reference_parse_node.py
│   │   │   │   ├── test_fl_row_reference_parse_node.py
│   │   │   │   ├── test_parse_node.py
│   │   │   │   ├── test_parse_node_constructors.py
│   │   │   │   └── test_parser.py
│   │   │   ├── test_calculate.py
│   │   │   ├── test_cell.py
│   │   │   ├── test_cell_range.py
│   │   │   ├── test_clipboard.py
│   │   │   ├── test_dependency_graph.py
│   │   │   ├── test_dirigible_datetime.py
│   │   │   ├── test_errors.py
│   │   │   ├── test_eval_constant.py
│   │   │   ├── test_forms.py
│   │   │   ├── test_formula_interpreter.py
│   │   │   ├── test_importer.py
│   │   │   ├── test_rewrite_formula_offset_cell_references.py
│   │   │   ├── test_sheet.py
│   │   │   ├── test_ui_jsonifier.py
│   │   │   ├── test_views.py
│   │   │   ├── test_views_api_0_1.py
│   │   │   ├── test_worksheet.py
│   │   │   └── utils/
│   │   │       ├── __init__.py
│   │   │       ├── test_cell_name_utils.py
│   │   │       ├── test_interruptable_thread.py
│   │   │       └── test_string_utils.py
│   │   ├── ui_jsonifier.py
│   │   ├── urls.py
│   │   ├── urls_api_0_1.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── cell_name_utils.py
│   │   │   ├── interruptable_thread.py
│   │   │   └── string_utils.py
│   │   ├── views.py
│   │   ├── views_api_0_1.py
│   │   └── worksheet.py
│   └── user/
│       ├── __init__.py
│       ├── admin.py
│       ├── forms.py
│       ├── migrations/
│       │   ├── 0001_initial.py
│       │   └── __init__.py
│       ├── models.py
│       ├── signup_urls.py
│       ├── templates/
│       │   ├── login.html
│       │   ├── registration/
│       │   │   ├── activate.html
│       │   │   ├── activation_email.txt
│       │   │   ├── activation_email_subject.txt
│       │   │   ├── registration_complete.html
│       │   │   └── registration_form.html
│       │   ├── user_page.html
│       │   └── welcome_email.txt
│       ├── tests/
│       │   ├── __init__.py
│       │   ├── test_forms.py
│       │   ├── test_models.py
│       │   └── test_views.py
│       ├── urls.py
│       └── views.py
├── documentation/
│   ├── .gitignore
│   ├── BeautifulSoup.py
│   ├── Makefile
│   ├── _static/
│   │   └── file-to-force-git-to-keep-empty-dir
│   ├── _templates/
│   │   └── layout.html
│   ├── builtins.rst
│   ├── conf.py
│   ├── dirigible-theme/
│   │   ├── layout.html
│   │   ├── static/
│   │   │   └── dirigible-style.css
│   │   └── theme.conf
│   ├── fl-python-differences.rst
│   ├── import_export.rst
│   ├── index.rst
│   ├── json_api.rst
│   ├── overview.rst
│   ├── public_sheets.rst
│   ├── python-modules.rst
│   ├── spreadsheet-functions.rsl
│   ├── spreadsheet-functions.rst
│   ├── talk.md
│   ├── talk_example_sheets.json
│   ├── tutorial01.rst
│   ├── tutorial02.rst
│   ├── tutorial03.rst
│   └── tutorial04.rst
└── requirements.txt
Download .txt
SYMBOL INDEX (1979 symbols across 215 files)

FILE: dirigible/dirigible/test_utils.py
  function create_suite_for_file_directory (line 16) | def create_suite_for_file_directory(file):
  function die (line 26) | def die(exception=None):
  class ResolverTestMixins (line 35) | class ResolverTestMixins(object):
    method assertCalledOnce (line 36) | def assertCalledOnce(self, mock, *args, **kwargs):
  class ResolverTestCase (line 43) | class ResolverTestCase(unittest.TestCase, ResolverTestMixins):
  class ResolverDjangoTestCase (line 48) | class ResolverDjangoTestCase(django.test.TestCase, ResolverTestMixins):
  function assert_security_classes_exist (line 61) | def assert_security_classes_exist(test, module_name, excludes=None):

FILE: dirigible/featured_sheet/models.py
  class FeaturedSheet (line 9) | class FeaturedSheet(models.Model):
    method __unicode__ (line 14) | def __unicode__(self):

FILE: dirigible/featured_sheet/tests/test_models.py
  class TestFeaturedSheetModel (line 12) | class TestFeaturedSheetModel(ResolverTestCase):
    method test_can_construct_without_more_info_url (line 14) | def test_can_construct_without_more_info_url(self):
    method test_can_construct_with_more_info_url (line 29) | def test_can_construct_with_more_info_url(self):
    method test_unicode (line 45) | def test_unicode(self):

FILE: dirigible/feedback/tests/test_views.py
  class SubmitTest (line 16) | class SubmitTest(ResolverTestCase):
    method test_submit_with_message_and_email_address_and_username_sends_admin_email_with_all_three (line 19) | def test_submit_with_message_and_email_address_and_username_sends_admi...

FILE: dirigible/feedback/views.py
  function submit (line 13) | def submit(request):

FILE: dirigible/fts/tests/functionaltest.py
  function _debug (line 47) | def _debug(text):
  class Url (line 53) | class Url(object):
    method user_page (line 64) | def user_page(cls, username):
    method sheet_page (line 68) | def sheet_page(cls, username, sheet_id):
    method api_url (line 72) | def api_url(cls, username, sheet_id):
  function snapshot_on_error (line 77) | def snapshot_on_error(test):
  function humanesque_delay (line 103) | def humanesque_delay(length=DEFAULT_TYPING_WAIT):
  function humanise_with_delay (line 107) | def humanise_with_delay(action):
  class Bounds (line 117) | class Bounds(object):
    method __init__ (line 118) | def __init__(self, width, height, top, left):
  function convert_rgb_to_hex (line 131) | def convert_rgb_to_hex(value):
  class FunctionalTest (line 137) | class FunctionalTest(StaticLiveServerTestCase):
    method wait_for (line 140) | def wait_for(
    method get_dump_filename (line 164) | def get_dump_filename(self):
    method create_users (line 174) | def create_users(self):
    method setUp (line 193) | def setUp(self):
    method tearDown (line 201) | def tearDown(self):
    method login (line 207) | def login(
    method logout (line 233) | def logout(self):
    method get_element (line 237) | def get_element(self, locator):
    method is_element_focused (line 245) | def is_element_focused(self, locator):
    method is_element_present (line 251) | def is_element_present(self, locator):
    method get_text (line 259) | def get_text(self, locator):
    method get_value (line 263) | def get_value(self, locator):
    method human_key_press (line 267) | def human_key_press(self, key_code):
    method key_down (line 273) | def key_down(self, key_code):
    method click_to_and_blur_from (line 282) | def click_to_and_blur_from(self, click_to_locator, blur_from_locator):
    method get_element_bounds (line 287) | def get_element_bounds(self, locator):
    method get_css_property (line 296) | def get_css_property(self, jquery_locator, property_name):
    method assert_urls_are_same (line 310) | def assert_urls_are_same(self, actual, expected):
    method assert_HTTP_error (line 317) | def assert_HTTP_error(self, url, error_code):
    method assert_redirects (line 326) | def assert_redirects(self, from_url, to_url):
    method is_element_enabled (line 333) | def is_element_enabled(self, element_id):
    method wait_for_element_presence (line 339) | def wait_for_element_presence(
    method wait_for_element_to_appear (line 353) | def wait_for_element_to_appear(self, locator, timeout_seconds=DEFAULT_...
    method wait_for_element_text (line 357) | def wait_for_element_text(self, locator, text, timeout_seconds=DEFAULT...
    method wait_for_element_visibility (line 365) | def wait_for_element_visibility(self, locator, visibility, timeout_sec...
    method get_url_with_session_cookie (line 373) | def get_url_with_session_cookie(self, url, data=None):
    method create_new_sheet (line 384) | def create_new_sheet(self, username=None, manually=False):
    method login_and_create_new_sheet (line 395) | def login_and_create_new_sheet(self, username=None):
    method get_my_usernames (line 400) | def get_my_usernames(self):
    method get_my_username (line 413) | def get_my_username(self):
    method _check_page_link_home (line 417) | def _check_page_link_home(self):
    method check_page_load (line 437) | def check_page_load(self, link_destination=None):
    method go_to_url (line 441) | def go_to_url(self, url):
    method refresh_sheet_page (line 447) | def refresh_sheet_page(self):
    method click_link (line 452) | def click_link(self, element_id):
    method set_sheet_name (line 457) | def set_sheet_name(self, name):
    method assert_sends_to_login_page (line 470) | def assert_sends_to_login_page(self, requested_url):
    method assert_sends_to_root_page (line 474) | def assert_sends_to_root_page(self, requested_url):
    method assert_page_title_contains (line 478) | def assert_page_title_contains(self, link_url, title):
    method assert_has_useful_information_links (line 485) | def assert_has_useful_information_links(self):
    method get_cell_css (line 491) | def get_cell_css(self, column, row, must_be_active=False):
    method get_cell_locator (line 500) | def get_cell_locator(self, column, row, must_be_active=False):
    method get_cell_formatted_value_locator (line 504) | def get_cell_formatted_value_locator(self, column, row, raise_if_cell_...
    method get_active_cell_editor_locator (line 517) | def get_active_cell_editor_locator(self):
    method get_cell_editor_locator (line 521) | def get_cell_editor_locator(self, column, row):
    method get_cell_editor (line 526) | def get_cell_editor(self):
    method is_cell_visible (line 530) | def is_cell_visible(self, column, row):
    method assert_cell_visible (line 564) | def assert_cell_visible(self, column, row):
    method wait_for_cell_to_be_visible (line 571) | def wait_for_cell_to_be_visible(
    method get_formula_bar_id (line 582) | def get_formula_bar_id(self):
    method get_formula_bar_locator (line 586) | def get_formula_bar_locator(self):
    method is_formula_bar_enabled (line 590) | def is_formula_bar_enabled(self):
    method scroll_cell_row_into_view (line 594) | def scroll_cell_row_into_view(self, column, row):
    method go_to_cell (line 601) | def go_to_cell(self, column, row):
    method click_on_cell (line 608) | def click_on_cell(self, column, row):
    method select_range_with_shift_click (line 613) | def select_range_with_shift_click(self, start, end):
    method mouse_drag (line 620) | def mouse_drag(self, cell_from, cell_to):
    method assert_current_selection (line 638) | def assert_current_selection(self, topleft, bottomright, thoroughly=Tr...
    method open_cell_for_editing (line 653) | def open_cell_for_editing(self, column, row):
    method type_into_cell_editor_unhumanized (line 661) | def type_into_cell_editor_unhumanized(self, text):
    method enter_cell_text (line 666) | def enter_cell_text(self, col, row, text):
    method enter_cell_text_unhumanized (line 670) | def enter_cell_text_unhumanized(self, col, row, text):
    method get_current_cell (line 677) | def get_current_cell(self):
    method get_cell_text (line 687) | def get_cell_text(self, column, row):
    method get_cell_editor_content (line 693) | def get_cell_editor_content(self):
    method get_cell_shown_formula_locator (line 697) | def get_cell_shown_formula_locator(self, column, row, raise_if_cell_mi...
    method get_cell_shown_formula (line 707) | def get_cell_shown_formula(self, column, row, raise_if_cell_missing=Tr...
    method assert_cell_shown_formula (line 718) | def assert_cell_shown_formula(self, column, row, formula):
    method wait_for_cell_shown_formula (line 722) | def wait_for_cell_shown_formula(self, column, row, formula, timeout_se...
    method wait_for_cell_to_contain_formula (line 737) | def wait_for_cell_to_contain_formula(self, column, row, formula):
    method get_cell_error (line 745) | def get_cell_error(self, column, row):
    method assert_cell_has_error (line 750) | def assert_cell_has_error(self, column, row, error_text):
    method assert_cell_has_no_error (line 755) | def assert_cell_has_no_error(self, column, row):
    method assert_cell_is_current_but_not_editing (line 762) | def assert_cell_is_current_but_not_editing(self, col, row):
    method assert_cell_is_current_and_is_editing (line 769) | def assert_cell_is_current_and_is_editing(self, col, row):
    method wait_for_cell_value (line 776) | def wait_for_cell_value(
    method wait_for_cell_to_become_active (line 827) | def wait_for_cell_to_become_active(
    method wait_for_cell_to_enter_edit_mode (line 840) | def wait_for_cell_to_enter_edit_mode(
    method wait_for_cell_editor_content (line 852) | def wait_for_cell_editor_content(self, content):
    method get_viewport_top (line 861) | def get_viewport_top(self):
    method get_viewport_bottom (line 867) | def get_viewport_bottom(self):
    method is_spinner_visible (line 873) | def is_spinner_visible(self):
    method wait_for_spinner_to_stop (line 880) | def wait_for_spinner_to_stop(self, timeout_seconds=DEFAULT_WAIT_FOR_TI...
    method wait_for_grid_to_appear (line 888) | def wait_for_grid_to_appear(self, timeout_seconds=DEFAULT_WAIT_FOR_TIM...
    method get_usercode (line 892) | def get_usercode(self):
    method enter_usercode (line 899) | def enter_usercode(self, code, commit_change=True):
    method append_usercode (line 909) | def append_usercode(self, code):
    method prepend_usercode (line 913) | def prepend_usercode(self, code):
    method wait_for_usercode_editor_content (line 917) | def wait_for_usercode_editor_content(
    method sanitise_console_content (line 932) | def sanitise_console_content(self, content):
    method get_console_content (line 938) | def get_console_content(self):
    method wait_for_console_content (line 943) | def wait_for_console_content(self, content, timeout_seconds=DEFAULT_WA...
    method get_formula_bar_contents (line 951) | def get_formula_bar_contents(self):
    method assert_formula_bar_contains (line 955) | def assert_formula_bar_contains(self, contents):
    method wait_for_formula_bar_contents (line 959) | def wait_for_formula_bar_contents(self, contents, timeout_seconds=DEFA...
    method click_formula_bar (line 966) | def click_formula_bar(self):
    method copy_range (line 974) | def copy_range(self, start, end):
    method cut_range (line 983) | def cut_range(self, start, end):
    method paste_range (line 993) | def paste_range(self, start, end=None):
    method set_filename_for_upload (line 1003) | def set_filename_for_upload(self, file_name, field_selector):
    method pop_email_for_client (line 1025) | def pop_email_for_client(self, email_address, fail_if_none=True, conte...
    method _pop_email_for_client_once (line 1039) | def _pop_email_for_client_once(self, email_address, content_filter=None):
    method clear_email_for_address (line 1060) | def clear_email_for_address(self, email_address, content_filter=None):
    method all_emails (line 1071) | def all_emails(self, server):

FILE: dirigible/fts/tests/test_2521_CodeEditor.py
  class Test_2521_CodeEditor (line 11) | class Test_2521_CodeEditor(FunctionalTest):
    method test_code_editor_tabs_and_indents (line 13) | def test_code_editor_tabs_and_indents(self):
    method test_code_editor_shows_errors (line 85) | def test_code_editor_shows_errors(self):
    method get_editor_selected_range (line 145) | def get_editor_selected_range(self):
    method assert_editor_line_visible (line 158) | def assert_editor_line_visible(self, line):
    method test_code_editor_find_function (line 170) | def test_code_editor_find_function(self):
    method test_code_editor_go_to_line_function (line 202) | def test_code_editor_go_to_line_function(self):

FILE: dirigible/fts/tests/test_2525_LoginLogout.py
  class Test_2525_LoginLogout (line 10) | class Test_2525_LoginLogout(FunctionalTest):
    method assert_login_error_shown (line 14) | def assert_login_error_shown(self):
    method test_login_happy_path (line 21) | def test_login_happy_path(self):
    method test_login (line 48) | def test_login(self):
    method test_legacy_dashboard_link_takes_you_to_root_url (line 195) | def test_legacy_dashboard_link_takes_you_to_root_url(self):

FILE: dirigible/fts/tests/test_2528_CreateEditSheet.py
  class Test_2528_CreateEditSheet (line 11) | class Test_2528_CreateEditSheet(FunctionalTest):
    method assert_editing_cell (line 14) | def assert_editing_cell(self, column, row):
    method test_create_edit_sheet (line 21) | def test_create_edit_sheet(self):
    method test_new_sheet_not_logged_in (line 168) | def test_new_sheet_not_logged_in(self):
    method test_access_sheet_with_incorrect_user_id (line 183) | def test_access_sheet_with_incorrect_user_id(self):

FILE: dirigible/fts/tests/test_2529_HighlightErrorsInCells.py
  class Test_2529_HighlightErrorsInCells (line 8) | class Test_2529_HighlightErrorsInCells(FunctionalTest):
    method test_highlight_errors_in_cells (line 10) | def test_highlight_errors_in_cells(self):

FILE: dirigible/fts/tests/test_2531_DifficultStuffInCells.py
  class Test_2531_DifficultStuffInCells (line 10) | class Test_2531_DifficultStuffInCells(FunctionalTest):
    method test_list_in_cell (line 13) | def test_list_in_cell(self):
    method test_dictionary_in_cell (line 30) | def test_dictionary_in_cell(self):
    method test_object_in_cell (line 42) | def test_object_in_cell(self):
    method assert_input_roundtrips (line 71) | def assert_input_roundtrips(self, typed):
    method test_html_chars_escaped (line 85) | def test_html_chars_escaped(self):
    method test_numeric_types (line 99) | def test_numeric_types(self):

FILE: dirigible/fts/tests/test_2532_LambdasInCells.py
  class Test_2532_LambdasInCells (line 15) | class Test_2532_LambdasInCells(FunctionalTest):
    method test_lambda_in_cell (line 18) | def test_lambda_in_cell(self):

FILE: dirigible/fts/tests/test_2533_Numpy.py
  class Test_2533_Numpy (line 9) | class Test_2533_Numpy(FunctionalTest):
    method test_numpy_tutorial_create_arrays (line 12) | def test_numpy_tutorial_create_arrays(self):
    method test_numpy_tutorial_basic_operations (line 69) | def test_numpy_tutorial_basic_operations(self):

FILE: dirigible/fts/tests/test_2534_JsonWorksheets.py
  class Test_2534_JsonWorksheets_v0_1 (line 16) | class Test_2534_JsonWorksheets_v0_1(FunctionalTest):
    method enable_json_api_for_sheet (line 18) | def enable_json_api_for_sheet(self):
    method test_simple_json (line 27) | def test_simple_json(self):
    method test_simple_json_with_error (line 62) | def test_simple_json_with_error(self):
    method test_simple_json_with_overrides_get (line 98) | def test_simple_json_with_overrides_get(self):
    method test_simple_json_with_overrides_post (line 145) | def test_simple_json_with_overrides_post(self):

FILE: dirigible/fts/tests/test_2535_RunWorksheetSerial.py
  class Test_2535_RunWorksheet (line 9) | class Test_2535_RunWorksheet(FunctionalTest):
    method test_run_worksheet_no_overrides (line 11) | def test_run_worksheet_no_overrides(self):
    method test_run_worksheet_with_overrides (line 34) | def test_run_worksheet_with_overrides(self):
    method test_run_worksheet_with_error (line 67) | def test_run_worksheet_with_error(self):

FILE: dirigible/fts/tests/test_2536_ParallelFormulaExecution.py
  class Test_2536_ParallelFormulaExecution (line 17) | class Test_2536_ParallelFormulaExecution(FunctionalTest):
    method get_last_recalc_time (line 19) | def get_last_recalc_time(self):
    method test_formulae_executed_in_parallel (line 24) | def test_formulae_executed_in_parallel(self):
    method test_run_worksheet_executed_in_parallel (line 60) | def test_run_worksheet_executed_in_parallel(self):

FILE: dirigible/fts/tests/test_2537_ErrorsInConsole.py
  class Test_2537_ErrorsInConsole (line 8) | class Test_2537_ErrorsInConsole(FunctionalTest):
    method test_console (line 10) | def test_console(self):
    method test_formula_error_in_console (line 40) | def test_formula_error_in_console(self):
    method test_formula_errors_precede_usercode_errors_in_console (line 68) | def test_formula_errors_precede_usercode_errors_in_console(self):

FILE: dirigible/fts/tests/test_2538_ShowStdoutInConsole.py
  class Test_2538_ShowStdoutInConsole (line 10) | class Test_2538_ShowStdoutInConsole(FunctionalTest):
    method test_stdout_displayed_in_console (line 12) | def test_stdout_displayed_in_console(self):
    method test_output_interleaved_with_formula_errors (line 27) | def test_output_interleaved_with_formula_errors(self):

FILE: dirigible/fts/tests/test_2540_FrontPage.py
  class Test_2540_FrontPage (line 14) | class Test_2540_FrontPage(FunctionalTest):
    method check_url_not_broken (line 16) | def check_url_not_broken(self, url):
    method check_links_not_broken_for_tag_attribute (line 23) | def check_links_not_broken_for_tag_attribute(self, tag_xpath, attribute):
    method test_front_page_links (line 33) | def test_front_page_links(self):

FILE: dirigible/fts/tests/test_2544_403_404_and_500_pages.py
  class Test_2544_404And500Pages (line 10) | class Test_2544_404And500Pages(FunctionalTest):
    method test_403 (line 15) | def test_403(self):
    method test_404 (line 48) | def test_404(self):
    method test_500 (line 77) | def test_500(self):

FILE: dirigible/fts/tests/test_2545_PageResizeBehaviour.py
  class Test_2545_PageResizeBehaviour (line 9) | class Test_2545_PageResizeBehaviour(FunctionalTest):
    method test_splitters (line 12) | def test_splitters(self):
    method test_grid_resize (line 63) | def test_grid_resize(self):

FILE: dirigible/fts/tests/test_2546_ListSheetsOnDashboard.py
  class Test_2546_ListSheetsOnDashboard (line 10) | class Test_2546_ListSheetsOnDashboard(FunctionalTest):
    method rename_current_sheet (line 12) | def rename_current_sheet(self, name):
    method assert_sheet_is_listed (line 22) | def assert_sheet_is_listed(self, sheet_id, sheet_name=None):
    method test_list_exists (line 33) | def test_list_exists(self):

FILE: dirigible/fts/tests/test_2547_EnterDataQuickly.py
  class Test_2547_EnterDataQuickly (line 10) | class Test_2547_EnterDataQuickly(FunctionalTest):
    method test_enter_data_quickly (line 13) | def test_enter_data_quickly(self):
    method test_enter_data_quickly_in_batches (line 27) | def test_enter_data_quickly_in_batches(self):

FILE: dirigible/fts/tests/test_2548_UserCode.py
  class Test_2548_UserCode (line 10) | class Test_2548_UserCode(FunctionalTest):
    method test_editor_presence (line 13) | def test_editor_presence(self):
    method test_preformula_usercode (line 42) | def test_preformula_usercode(self):
    method test_postformula_usercode (line 70) | def test_postformula_usercode(self):

FILE: dirigible/fts/tests/test_2549_InterruptedRecalculations.py
  class Test_2549_InterruptedRecalculations (line 11) | class Test_2549_InterruptedRecalculations(FunctionalTest):
    method test_interrupted_recalc_coming_back_handled_correctly (line 14) | def test_interrupted_recalc_coming_back_handled_correctly(self):

FILE: dirigible/fts/tests/test_2550_EditableSheetName.py
  class Test_2550_EdittableSheetName (line 12) | class Test_2550_EdittableSheetName(FunctionalTest):
    method test_sheet_name_edittable (line 14) | def test_sheet_name_edittable(self):
    method test_changing_sheet_name_should_not_interrupt_recalc_but_still_succeeds (line 75) | def test_changing_sheet_name_should_not_interrupt_recalc_but_still_suc...

FILE: dirigible/fts/tests/test_2554_SlicingInFormulae.py
  class Test_2554_SlicingInFormulae (line 8) | class Test_2554_SlicingInFormulae(FunctionalTest):
    method test_formulas_work_properly (line 10) | def test_formulas_work_properly(self):

FILE: dirigible/fts/tests/test_2556_BrokenUserCode.py
  class test_2556_BrokenUsercode (line 8) | class test_2556_BrokenUsercode(FunctionalTest):
    method test_newly_entered_formulae_appear_grey_then_results_in_black (line 11) | def test_newly_entered_formulae_appear_grey_then_results_in_black(self):
    method test_broken_usercode_returns_as_much_as_it_can (line 29) | def test_broken_usercode_returns_as_much_as_it_can(self):

FILE: dirigible/fts/tests/test_2557_ClickAwaySavesUsercode.py
  class Test_2557_ClickAwaySavesUsercode (line 8) | class Test_2557_ClickAwaySavesUsercode(FunctionalTest):
    method test_blur_on_edit_textarea_saves_usercode (line 10) | def test_blur_on_edit_textarea_saves_usercode(self):

FILE: dirigible/fts/tests/test_2558_MoreCellsByDefault.py
  class Test_2558_MoreCellsByDefault (line 9) | class Test_2558_MoreCellsByDefault(FunctionalTest):
    method test_more_cells_by_default (line 11) | def test_more_cells_by_default(self):

FILE: dirigible/fts/tests/test_2559_FitEditorToCells.py
  class Test_2559_FitEditorToCells (line 9) | class Test_2559_FitEditorToCells(FunctionalTest):
    method test_editor_fits_cells (line 11) | def test_editor_fits_cells(self):

FILE: dirigible/fts/tests/test_2562_ErrorInCellShouldBeClearedByConstants.py
  class test_2562_ErrorInCellShouldBeClearedByConstants (line 8) | class test_2562_ErrorInCellShouldBeClearedByConstants(FunctionalTest):
    method test_ConstantsClearCellErrors (line 10) | def test_ConstantsClearCellErrors(self):

FILE: dirigible/fts/tests/test_2565_JSONAPIAuth.py
  class Test_2565_JSONAPIAuth (line 27) | class Test_2565_JSONAPIAuth(FunctionalTest):
    method test_json_api_auth (line 29) | def test_json_api_auth(self):
    method test_link_to_documentation_in_dialog (line 263) | def test_link_to_documentation_in_dialog(self):
    method test_run_worksheet_with_json_disabled_sheets (line 290) | def test_run_worksheet_with_json_disabled_sheets(self):
    method test_json_api_auth_reports_server_error (line 324) | def test_json_api_auth_reports_server_error(self):

FILE: dirigible/fts/tests/test_2571_DocumentationAndBlogLinks.py
  class Test_2571_Documentation (line 11) | class Test_2571_Documentation(FunctionalTest):
    method get_link_href (line 13) | def get_link_href(self, link_id):
    method test_main_documentation_page_exists (line 18) | def test_main_documentation_page_exists(self):

FILE: dirigible/fts/tests/test_2577_SaveColumnWidths.py
  class Test_2537_save_column_widths (line 13) | class Test_2537_save_column_widths(FunctionalTest):
    method get_column_header_locator (line 16) | def get_column_header_locator(self, column_name):
    method get_column_resize_handle_locator (line 20) | def get_column_resize_handle_locator(self, column_name):
    method get_column_width (line 24) | def get_column_width(self, column_name):
    method wait_for_column_width (line 28) | def wait_for_column_width(self, column_name, width):
    method resize_column (line 35) | def resize_column(self, column_name, width_delta):
    method test_save_em (line 47) | def test_save_em(self):
    method test_changing_column_widths_does_not_interrupt_recalc_but_does_save_widths (line 65) | def test_changing_column_widths_does_not_interrupt_recalc_but_does_sav...

FILE: dirigible/fts/tests/test_2581_FormulaBar.py
  class Test_2581_FormulaBar (line 9) | class Test_2581_FormulaBar(FunctionalTest):
    method wait_for_formula_bar_enabled (line 11) | def wait_for_formula_bar_enabled(self):
    method wait_for_formula_bar_disabled (line 17) | def wait_for_formula_bar_disabled(self):
    method test_formula_bar (line 23) | def test_formula_bar(self):
    method test_formula_bar_remains_enabled_at_all_times (line 136) | def test_formula_bar_remains_enabled_at_all_times(self):

FILE: dirigible/fts/tests/test_2582_ReferencingEmptyCell.py
  class Test_2582_ReferencingEmptyCell (line 9) | class Test_2582_ReferencingEmptyCell(FunctionalTest):
    method test_referencing_empty_cell (line 11) | def test_referencing_empty_cell(self):

FILE: dirigible/fts/tests/test_2592_Cut_Copy_Paste_Within_Dirigible.py
  class Test_2592_Cut_Copy_Paste_within_Dirigible (line 12) | class Test_2592_Cut_Copy_Paste_within_Dirigible(FunctionalTest):
    method wait_for_only_active_cell_selected (line 14) | def wait_for_only_active_cell_selected(self):
    method test_block_selection (line 33) | def test_block_selection(self):
    method assert_copy_and_paste (line 84) | def assert_copy_and_paste(
    method test_copy_and_paste_southeast (line 134) | def test_copy_and_paste_southeast(self):
    method test_copy_and_paste_northwest (line 148) | def test_copy_and_paste_northwest(self):
    method test_copy_and_paste_to_new_sheet (line 161) | def test_copy_and_paste_to_new_sheet(self):
    method test_cut_and_paste_southeast (line 180) | def test_cut_and_paste_southeast(self):
    method test_cut_and_paste_northwest (line 193) | def test_cut_and_paste_northwest(self):
    method test_cut_and_paste_to_new_sheet (line 206) | def test_cut_and_paste_to_new_sheet(self):
    method test_multiple_pastes_after_copy (line 216) | def test_multiple_pastes_after_copy(self):
    method test_multiple_pastes_after_cut (line 267) | def test_multiple_pastes_after_cut(self):
    method test_values_wo_formulae_are_promoted (line 310) | def test_values_wo_formulae_are_promoted(self):
    method test_target_range_is_cleared_before_paste (line 320) | def test_target_range_is_cleared_before_paste(self):
    method test_mouse_drags_dont_lose_current_cell_edits (line 336) | def test_mouse_drags_dont_lose_current_cell_edits(self):

FILE: dirigible/fts/tests/test_2595_Spinner.py
  class Test_2595_Throbber (line 9) | class Test_2595_Throbber(FunctionalTest):
    method test_spinner_appears_during_recalcs (line 11) | def test_spinner_appears_during_recalcs(self):

FILE: dirigible/fts/tests/test_2597_CapRecalcTime.py
  class Test_2597_CapRecalcTime (line 9) | class Test_2597_CapRecalcTime(FunctionalTest):
    method test_recalcs_get_stopped (line 11) | def test_recalcs_get_stopped(self):

FILE: dirigible/fts/tests/test_2601_UndefinedShouldBeAvailableToUsercode.py
  class Test_2601_UndefinedShouldBeAvailableToUsercode (line 8) | class Test_2601_UndefinedShouldBeAvailableToUsercode(FunctionalTest):
    method test_use_undefined (line 10) | def test_use_undefined(self):

FILE: dirigible/fts/tests/test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete.py
  class Test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete (line 10) | class Test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete(Function...
    method test_sheet_page_displays_fast (line 12) | def test_sheet_page_displays_fast(self):

FILE: dirigible/fts/tests/test_2603_WorksheetsMayOnlyContainCells.py
  class test_2603_WorksheetsMayOnlyContainCells (line 9) | class test_2603_WorksheetsMayOnlyContainCells(FunctionalTest):
    method test_setting_worksheet_location_to_non_cell_raises (line 11) | def test_setting_worksheet_location_to_non_cell_raises(self):

FILE: dirigible/fts/tests/test_2616_RootPageIsDashboard.py
  class Test_2616_RootPageIsDashboard (line 10) | class Test_2616_RootPageIsDashboard(FunctionalTest):
    method test_old_url_redirects (line 15) | def test_old_url_redirects(self):

FILE: dirigible/fts/tests/test_2621_CanSaveSheetsWithLotsOfFormulae.py
  class Test_2621_CanSaveSheetsWithLotsOfFormulae (line 10) | class Test_2621_CanSaveSheetsWithLotsOfFormulae(FunctionalTest):
    method test_can_save_lots_of_formulae (line 13) | def test_can_save_lots_of_formulae(self):

FILE: dirigible/fts/tests/test_2622_CellRanges.py
  class Test_2622_CellRanges (line 10) | class Test_2622_CellRanges(FunctionalTest):
    method test_can_use_cell_ranges_in_usercode (line 12) | def test_can_use_cell_ranges_in_usercode(self):
    method test_can_use_cell_ranges_in_formulae (line 60) | def test_can_use_cell_ranges_in_formulae(self):
    method test_bare_cell_ranges_in_cells_dont_cause_recursive_explosion (line 72) | def test_bare_cell_ranges_in_cells_dont_cause_recursive_explosion(self):
    method test_cellrange_dependencies (line 84) | def test_cellrange_dependencies(self):

FILE: dirigible/fts/tests/test_2631_BlogRedirect.py
  class Test_2631_BlogRedirect (line 27) | class Test_2631_BlogRedirect(unittest.TestCase):
    method test_blog_page_redirect (line 29) | def test_blog_page_redirect(self):
    method test_blog_rss_redirect (line 45) | def test_blog_rss_redirect(self):

FILE: dirigible/fts/tests/test_2633_CursorKeysMoveAroundGrid.py
  class Test_2633_CursorKeysMoveAroundGrid (line 11) | class Test_2633_CursorKeysMoveAroundGrid(FunctionalTest):
    method get_cell_editor_cursor_position (line 13) | def get_cell_editor_cursor_position(self):
    method assert_editing_cell_at_position (line 23) | def assert_editing_cell_at_position(self, col, row, position):
    method test_navigate_with_cursor_keys (line 29) | def test_navigate_with_cursor_keys(self):
    method test_formula_bar_contents_should_follow_current_cell (line 192) | def test_formula_bar_contents_should_follow_current_cell(self):
    method test_down_and_enter_keys_commit_edit_and_move_current_cell_down (line 267) | def test_down_and_enter_keys_commit_edit_and_move_current_cell_down(se...
    method test_begin_typing_enters_edit_mode (line 325) | def test_begin_typing_enters_edit_mode(self):
    method test_cursor_keys_while_editing (line 377) | def test_cursor_keys_while_editing(self):
    method test_editor_font_size_is_consistent (line 420) | def test_editor_font_size_is_consistent(self):
    method test_enter_single_character (line 441) | def test_enter_single_character(self):

FILE: dirigible/fts/tests/test_2635_SheetNameSelectedOnEdit.py
  class Test_2635_SheetNameSelectedOnEdit (line 14) | class Test_2635_SheetNameSelectedOnEdit(FunctionalTest):
    method test_click_on_sheet_name (line 16) | def test_click_on_sheet_name(self):

FILE: dirigible/fts/tests/test_2639_SciPy_and_MpMath.py
  class Test_2639_SciPy_and_MpMath (line 8) | class Test_2639_SciPy_and_MpMath(FunctionalTest):
    method test_can_use_scipy_norm (line 10) | def test_can_use_scipy_norm(self):
    method test_can_use_mpmath (line 29) | def test_can_use_mpmath(self):

FILE: dirigible/fts/tests/test_2642_RecalcTimesInConsole.py
  class Test_2642_RecalcTimesInConsole (line 13) | class Test_2642_RecalcTimesInConsole(FunctionalTest):
    method test_recalc_time_appears_in_console (line 15) | def test_recalc_time_appears_in_console(self):

FILE: dirigible/fts/tests/test_2644_AdminOmniscience.py
  class Test_2644_AdminOmniscience (line 8) | class Test_2644_AdminOmniscience(FunctionalTest):
    method test_staff_can_see_everything (line 11) | def test_staff_can_see_everything(self):
    method test_non_staff_cannot_view_or_edit_other_users_sheets_or_json (line 30) | def test_non_staff_cannot_view_or_edit_other_users_sheets_or_json(self):

FILE: dirigible/fts/tests/test_2650_UsercodeSandbox.py
  class Test_2650_UsercodeSandbox (line 14) | class Test_2650_UsercodeSandbox(FunctionalTest):
    method test_dirigible_package_is_off_limits (line 16) | def test_dirigible_package_is_off_limits(self):
    method test_dirigible_settings_not_accessible (line 30) | def test_dirigible_settings_not_accessible(self):
    method test_sys_path_omits_dirigible_dirs (line 43) | def test_sys_path_omits_dirigible_dirs(self):
    method test_harold_looks_at_his_root_directory (line 63) | def test_harold_looks_at_his_root_directory(self):
    method test_harold_tries_to_create_a_file_in_cwd (line 75) | def test_harold_tries_to_create_a_file_in_cwd(self):
    method test_harold_tries_to_create_a_file_in_usr (line 91) | def test_harold_tries_to_create_a_file_in_usr(self):

FILE: dirigible/fts/tests/test_2651_SaveSheetNameOnBlur.py
  class Test_2651_SaveSheetNameOnBlur (line 13) | class Test_2651_SaveSheetNameOnBlur(FunctionalTest):
    method test_blur_saves_sheet_name (line 15) | def test_blur_saves_sheet_name(self):
    method test_cancel_instruction_present (line 39) | def test_cancel_instruction_present(self):

FILE: dirigible/fts/tests/test_2652_CommitCellOnBlur.py
  class Test_2652_CommitCellOnBlur (line 13) | class Test_2652_CommitCellOnBlur(FunctionalTest):
    method test_blur_cell_saves_cell_contents (line 15) | def test_blur_cell_saves_cell_contents(self):
    method test_blur_formula_bar_saves_cell_contents (line 38) | def test_blur_formula_bar_saves_cell_contents(self):

FILE: dirigible/fts/tests/test_2654_CtrlSSavesUsercode.py
  class Test_2654_CtrlSSavesUsercode (line 10) | class Test_2654_CtrlSSavesUsercode(FunctionalTest):
    method test_ctrl_s_saves_usercode (line 12) | def test_ctrl_s_saves_usercode(self):

FILE: dirigible/fts/tests/test_2678_GlobalStateNotShared.py
  class Test_2678_GlobalStateNotShared (line 9) | class Test_2678_GlobalStateNotShared(FunctionalTest):
    method test_global_state_not_shared (line 12) | def test_global_state_not_shared(self):

FILE: dirigible/fts/tests/test_2682_CellAccessUsingA1.py
  class Test_2682_CellAccessUsingA1 (line 10) | class Test_2682_CellAccessUsingA1(FunctionalTest):
    method test_cell_access (line 12) | def test_cell_access(self):

FILE: dirigible/fts/tests/test_2685_ChangePassword.py
  class Test_2685_ChangePassword (line 9) | class Test_2685_ChangePassword(FunctionalTest):
    method test_change_password (line 11) | def test_change_password(self):

FILE: dirigible/fts/tests/test_2689_DontClearCellEditorWhenRecalcsHitClient.py
  class Test_2689_DontClearCellEditorOrFormulaBarWhenRecalcsHitClient (line 12) | class Test_2689_DontClearCellEditorOrFormulaBarWhenRecalcsHitClient(Func...
    method test_cell_editor_not_cleared (line 14) | def test_cell_editor_not_cleared(self):
    method test_formula_bar_not_cleared (line 43) | def test_formula_bar_not_cleared(self):

FILE: dirigible/fts/tests/test_2690_FocusShouldStartInGrid.py
  class test_2690_FocusShouldStartInGrid (line 9) | class test_2690_FocusShouldStartInGrid(FunctionalTest):
    method test_focus (line 11) | def test_focus(self):

FILE: dirigible/fts/tests/test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants.py
  class Test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants (line 15) | class Test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants(Functi...
    method test_load_constants_doesnt_trash_cells (line 17) | def test_load_constants_doesnt_trash_cells(self):

FILE: dirigible/fts/tests/test_2701_NameResolutionWorks.py
  class Test_2701_NameResolutionWorks (line 10) | class Test_2701_NameResolutionWorks(FunctionalTest):
    method test_name_resolution (line 12) | def test_name_resolution(self):

FILE: dirigible/fts/tests/test_2702_HttpsInChrootJail.py
  class Test_2702_HttpsInChrootJail (line 10) | class Test_2702_HttpsInChrootJail(FunctionalTest):
    method test_numpy_tutorial_create_arrays (line 12) | def test_numpy_tutorial_create_arrays(self):

FILE: dirigible/fts/tests/test_2704_OldStyleClassesInTheGrid.py
  class Test_2704_OldStyleClassesInTheGrid (line 11) | class Test_2704_OldStyleClassesInTheGrid(FunctionalTest):
    method test_put_old_style_classes_in_grid (line 13) | def test_put_old_style_classes_in_grid(self):

FILE: dirigible/fts/tests/test_2711_ImportExcel.py
  class Test_2711_Import_Excel (line 14) | class Test_2711_Import_Excel(FunctionalTest):
    method test_can_import_excel_values_only_from_sheet_page (line 16) | def test_can_import_excel_values_only_from_sheet_page(self):
    method test_bad_files_are_gracefully_handled (line 125) | def test_bad_files_are_gracefully_handled(self):

FILE: dirigible/fts/tests/test_2712_ImportCSV.py
  class Test_2712_ImportCSV (line 10) | class Test_2712_ImportCSV(FunctionalTest):
    method test_can_import_excel_generated_csv_to_cursor_position (line 12) | def test_can_import_excel_generated_csv_to_cursor_position(self):
    method test_can_import_utf8_csv (line 119) | def test_can_import_utf8_csv(self):
    method test_bad_files_are_gracefully_handled (line 169) | def test_bad_files_are_gracefully_handled(self):

FILE: dirigible/fts/tests/test_2726_FormulaBarTextSelection.py
  class Test_2726_FormulaBarSelectionDefect (line 10) | class Test_2726_FormulaBarSelectionDefect(FunctionalTest):
    method test_can_select_text_in_formula_bar (line 12) | def test_can_select_text_in_formula_bar(self):

FILE: dirigible/fts/tests/test_2734_ClearCells.py
  class Test_2734_ClearCells (line 15) | class Test_2734_ClearCells(FunctionalTest):
    method test_delete_key_clears_selected_cells (line 17) | def test_delete_key_clears_selected_cells(self):
    method test_backspace_key_clears_selected_cells (line 21) | def test_backspace_key_clears_selected_cells(self):
    method assert_key_deletes_cells (line 25) | def assert_key_deletes_cells(self, key_code):
    method test_delete_key_while_editing_still_does_what_it_should (line 56) | def test_delete_key_while_editing_still_does_what_it_should(self):
    method test_backspace_key_while_editing_still_does_what_it_should (line 77) | def test_backspace_key_while_editing_still_does_what_it_should(self):
    method test_can_clear_cell_from_usercode (line 97) | def test_can_clear_cell_from_usercode(self):
    method test_can_clear_cell_range_from_usercode (line 132) | def test_can_clear_cell_range_from_usercode(self):

FILE: dirigible/fts/tests/test_2735_CtrlKeysArePassedOnToBrowser.py
  class Test_2735_CtrlKeysArePassedToBrowser (line 11) | class Test_2735_CtrlKeysArePassedToBrowser(FunctionalTest):
    method test_ctrl_t (line 13) | def test_ctrl_t(self):

FILE: dirigible/fts/tests/test_2741_Xlrd.py
  class Test_2741_Xlrd (line 8) | class Test_2741_Xlrd(FunctionalTest):
    method test_can_use_xlrd (line 10) | def test_can_use_xlrd(self):

FILE: dirigible/fts/tests/test_2749_DisallowArbitraryKeysForWorksheet.py
  class Test_2749_DisallowArbitraryKeysForWorksheet (line 8) | class Test_2749_DisallowArbitraryKeysForWorksheet(FunctionalTest):
    method test_cant_use_silly_worksheet_keys (line 10) | def test_cant_use_silly_worksheet_keys(self):

FILE: dirigible/fts/tests/test_2751_UsefulModules.py
  class test_2751_UsefulModules (line 10) | class test_2751_UsefulModules(FunctionalTest):
    method test_can_import_useful_modules (line 12) | def test_can_import_useful_modules(self):

FILE: dirigible/fts/tests/test_2758_LoadGridDataOnDemand.py
  class Test_2758_LoadGridDataOnDemand (line 13) | class Test_2758_LoadGridDataOnDemand(FunctionalTest):
    method test_grid_data_loaded_on_demand_for_rows (line 15) | def test_grid_data_loaded_on_demand_for_rows(self):

FILE: dirigible/fts/tests/test_2762_PythonConversion.py
  class Test_2762_PythonConversion (line 8) | class Test_2762_PythonConversion(FunctionalTest):
    method test_formulas_work_properly (line 10) | def test_formulas_work_properly(self):

FILE: dirigible/fts/tests/test_2770_ClearDependentCellErrors.py
  class Test_2770_ClearDependentCellErrors (line 8) | class Test_2770_ClearDependentCellErrors(FunctionalTest):
    method test_dependent_cell_errors_are_cleared (line 10) | def test_dependent_cell_errors_are_cleared(self):

FILE: dirigible/fts/tests/test_2774_ExportCSV.py
  class Test_2774_ExportCSV (line 14) | class Test_2774_ExportCSV(FunctionalTest):
    method test_can_export_csv (line 16) | def test_can_export_csv(self):
    method test_can_export_unicode (line 92) | def test_can_export_unicode(self):

FILE: dirigible/fts/tests/test_2781_FormulaAndFormattedValueMustBeStrings.py
  class Test_2781_FormulaAndFormattedValueMustBeStrings (line 10) | class Test_2781_FormulaAndFormattedValueMustBeStrings(FunctionalTest):
    method test_str_formula_and_formatted_value (line 12) | def test_str_formula_and_formatted_value(self):

FILE: dirigible/fts/tests/test_2787_SignUp.py
  class Test_2787_SignUp (line 13) | class Test_2787_SignUp(FunctionalTest):
    method are_password_fields_showing_error (line 15) | def are_password_fields_showing_error(self):
    method test_can_sign_up_from_signup_page (line 22) | def test_can_sign_up_from_signup_page(self):

FILE: dirigible/fts/tests/test_2789_ErrorConsoleHTMLEscape.py
  class Test_2789_ErrorConsoleHTMLEscape (line 8) | class Test_2789_ErrorConsoleHTMLEscape(FunctionalTest):
    method test_error_console_output_is_escaped (line 10) | def test_error_console_output_is_escaped(self):

FILE: dirigible/fts/tests/test_2795_Rewrite_Formulae_during_Cut_and_Paste.py
  class Test_2795_Rewrite_Formulae_during_Cut_and_Paste (line 8) | class Test_2795_Rewrite_Formulae_during_Cut_and_Paste(FunctionalTest):
    method test_cut_cell_reference_to_cut_cell_is_rewritten (line 10) | def test_cut_cell_reference_to_cut_cell_is_rewritten(self):
    method test_cut_cell_reference_to_uncut_cell_is_not_rewritten (line 29) | def test_cut_cell_reference_to_uncut_cell_is_not_rewritten(self):
    method test_copied_cell_reference_to_copied_cell_is_rewritten (line 47) | def test_copied_cell_reference_to_copied_cell_is_rewritten(self):
    method test_copied_cell_reference_to_uncopied_cell_is_rewritten (line 66) | def test_copied_cell_reference_to_uncopied_cell_is_rewritten(self):
    method test_cut_cellrange_reference_to_completely_cut_cellrange_is_rewritten (line 84) | def test_cut_cellrange_reference_to_completely_cut_cellrange_is_rewrit...
    method test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rewritten (line 102) | def test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rew...
    method test_cut_cellrange_reference_to_uncut_cellrange_is_not_rewritten (line 120) | def test_cut_cellrange_reference_to_uncut_cellrange_is_not_rewritten(s...
    method test_copied_cellrange_reference_to_completely_copied_cellrange_is_rewritten (line 138) | def test_copied_cellrange_reference_to_completely_copied_cellrange_is_...
    method test_copied_cellrange_reference_to_partially_copied_cellrange_is_rewritten (line 156) | def test_copied_cellrange_reference_to_partially_copied_cellrange_is_r...
    method test_copied_cellrange_reference_to_uncopied_cellrange_is_rewritten (line 174) | def test_copied_cellrange_reference_to_uncopied_cellrange_is_rewritten...
    method test_outside_cell_references_to_range_cut_from_ARE_rewritten (line 192) | def test_outside_cell_references_to_range_cut_from_ARE_rewritten(self):
    method test_outside_cell_ranges_pointing_inside_range_cut_from_ARE_rewritten (line 212) | def test_outside_cell_ranges_pointing_inside_range_cut_from_ARE_rewrit...
    method test_absolute_references_in_copied_range_to_outside_are_not_rewritten (line 232) | def test_absolute_references_in_copied_range_to_outside_are_not_rewrit...
    method test_absolute_references_in_copied_range_to_inside_are_not_rewritten (line 251) | def test_absolute_references_in_copied_range_to_inside_are_not_rewritt...
    method test_absolute_references_outside_copied_range_to_inside_are_not_rewritten (line 270) | def test_absolute_references_outside_copied_range_to_inside_are_not_re...
    method test_absolute_references_in_cut_range_to_outside_are_not_rewritten (line 288) | def test_absolute_references_in_cut_range_to_outside_are_not_rewritten...
    method test_absolute_references_in_cut_range_to_inside_are_rewritten (line 307) | def test_absolute_references_in_cut_range_to_inside_are_rewritten(self):
    method test_absolute_references_outside_cut_range_to_inside_are_rewritten (line 325) | def test_absolute_references_outside_cut_range_to_inside_are_rewritten...
    method test_column_absolute_references_are_partially_rewritten (line 343) | def test_column_absolute_references_are_partially_rewritten(self):
    method test_row_absolute_references_are_partially_rewritten (line 362) | def test_row_absolute_references_are_partially_rewritten(self):
    method test_cell_rewrites_that_go_off_grid_are_handled (line 381) | def test_cell_rewrites_that_go_off_grid_are_handled(self):
    method test_cellrange_rewrites_that_go_off_grid_are_handled (line 400) | def test_cellrange_rewrites_that_go_off_grid_are_handled(self):
    method test_cut_paste_paste_rewrites_formulae_for_2nd_paste (line 420) | def test_cut_paste_paste_rewrites_formulae_for_2nd_paste(self):
    method test_copy_paste_paste_always_rewrites_formulae (line 439) | def test_copy_paste_paste_always_rewrites_formulae(self):
    method test_buttons (line 458) | def test_buttons(self):

FILE: dirigible/fts/tests/test_2799_FillDownDuringPaste.py
  class Test_2799_fill_down_during_paste (line 9) | class Test_2799_fill_down_during_paste(FunctionalTest):
    method wait_for_cell_to_contain_formula (line 11) | def wait_for_cell_to_contain_formula(self, column, row, formula):
    method test_fill_down_formula_with_copy_and_paste (line 17) | def test_fill_down_formula_with_copy_and_paste(self):
    method test_fill_down_2x2_clipboard_into_3x5_selection (line 40) | def test_fill_down_2x2_clipboard_into_3x5_selection(self):

FILE: dirigible/fts/tests/test_2812_CutCopyPasteInEditMode.py
  class Test_2812_CutCopyPasteInEditMode (line 16) | class Test_2812_CutCopyPasteInEditMode(FunctionalTest):
    method test_delete_key_while_editing_still_does_what_it_should (line 18) | def test_delete_key_while_editing_still_does_what_it_should(self):

FILE: dirigible/fts/tests/test_2814_PublicWorksheets.py
  class Test_2814_PublicWorksheets (line 15) | class Test_2814_PublicWorksheets(FunctionalTest):
    method tearDown (line 20) | def tearDown(self):
    method waitForButtonToIndicateSheetIsPublic (line 26) | def waitForButtonToIndicateSheetIsPublic(self, public):
    method test_public_worksheets_visible_readonly_and_copiable_for_others (line 47) | def test_public_worksheets_visible_readonly_and_copiable_for_others(se...
    method test_admin_can_copy_non_public_sheets (line 320) | def test_admin_can_copy_non_public_sheets(self):
    method test_link_to_documentation_in_dialog (line 342) | def test_link_to_documentation_in_dialog(self):

FILE: dirigible/fts/tests/test_2828_GridShouldNotStealFocusOnRecalc.py
  class Test_2828_GridShouldNotStealFocusOnRecalc (line 11) | class Test_2828_GridShouldNotStealFocusOnRecalc(FunctionalTest):
    method test_recalc_doesnt_steal_focus_from_usercode (line 14) | def test_recalc_doesnt_steal_focus_from_usercode(self):

FILE: dirigible/fts/tests/test_2839_CutCopyPasteButtons.py
  class Test_2839_CutCopyPasteButtons (line 8) | class Test_2839_CutCopyPasteButtons(FunctionalTest):
    method test_buttons_exist_and_are_clickable (line 10) | def test_buttons_exist_and_are_clickable(self):

FILE: dirigible/fts/tests/test_2844_CantMakeRowHeaderActive.py
  class Test_2844_CantMakeRowHeaderActive (line 8) | class Test_2844_CantMakeRowHeaderActive(FunctionalTest):
    method test_cant_make_row_header_active (line 10) | def test_cant_make_row_header_active(self):

FILE: dirigible/fts/tests/test_2848_WorksheetBounds.py
  class Test_2848_WorksheetBounds (line 8) | class Test_2848_WorksheetBounds(FunctionalTest):
    method test_access_worksheet_bounds (line 10) | def test_access_worksheet_bounds(self):

FILE: dirigible/fts/tests/test_2862_CopyAndPasteFormulaWithErrors.py
  class Test_2892_CopyAndPasteFormulaWithErrors (line 12) | class Test_2892_CopyAndPasteFormulaWithErrors(FunctionalTest):
    method test_recalc_doesnt_steal_focus_from_usercode (line 15) | def test_recalc_doesnt_steal_focus_from_usercode(self):

FILE: dirigible/fts/tests/test_2872_CellTooltips.py
  class Test_2892_CellTooltips (line 12) | class Test_2892_CellTooltips(FunctionalTest):
    method test_formulae_are_shown_in_tooltips (line 15) | def test_formulae_are_shown_in_tooltips(self):
    method test_formatted_values_are_shown_in_tooltips (line 33) | def test_formatted_values_are_shown_in_tooltips(self):

FILE: dirigible/fts/tests/test_2873_IE_Warning.py
  class Test_2873_IE_Warning (line 7) | class Test_2873_IE_Warning(FunctionalTest):
    method test_IE_warnings (line 9) | def test_IE_warnings(self):

FILE: dirigible/fts/tests/test_2884_FeedbackForm.py
  class Test_2884_FeedbackForm (line 8) | class Test_2884_FeedbackForm(FunctionalTest):
    method tearDown (line 10) | def tearDown(self):
    method test_feedback_dialog_from_non_logged_in_page (line 18) | def test_feedback_dialog_from_non_logged_in_page(self):
    method test_feedback_dialog_from_logged_in_dashboard (line 117) | def test_feedback_dialog_from_logged_in_dashboard(self):
    method test_feedback_dialog_displays_submission_status (line 188) | def test_feedback_dialog_displays_submission_status(self):

FILE: dirigible/info_pages/tests/test_views.py
  class TestFrontPageView (line 12) | class TestFrontPageView(ResolverTestCase):
    method test_should_delegate_to_non_logged_in_front_page_view_if_not_logged_in (line 15) | def test_should_delegate_to_non_logged_in_front_page_view_if_not_logge...
    method test_should_delegate_to_user_dashboard_if_are_logged_in (line 24) | def test_should_delegate_to_user_dashboard_if_are_logged_in(self, mock...
  class TestNonLoggedInFrontPageView (line 33) | class TestNonLoggedInFrontPageView(ResolverTestCase):
    method test_should_render_template_to_response_with_registration_form (line 36) | def test_should_render_template_to_response_with_registration_form(sel...
  class TestInfoPageView (line 47) | class TestInfoPageView(ResolverTestCase):
    method test_should_render_template_to_response_with_user (line 50) | def test_should_render_template_to_response_with_user(self, mock_rende...

FILE: dirigible/info_pages/views.py
  function front_page_view (line 10) | def front_page_view(request):
  function non_logged_in_front_page_view (line 17) | def non_logged_in_front_page_view(request):
  function info_page_view (line 21) | def info_page_view(request, template_name):

FILE: dirigible/registration/admin.py
  class RegistrationAdmin (line 6) | class RegistrationAdmin(admin.ModelAdmin):

FILE: dirigible/registration/forms.py
  class RegistrationForm (line 21) | class RegistrationForm(forms.Form):
    method clean_username (line 47) | def clean_username(self):
    method clean (line 59) | def clean(self):
    method save (line 72) | def save(self, profile_callback=None):
  class RegistrationFormTermsOfService (line 91) | class RegistrationFormTermsOfService(RegistrationForm):
  class RegistrationFormUniqueEmail (line 102) | class RegistrationFormUniqueEmail(RegistrationForm):
    method clean_email (line 108) | def clean_email(self):
  class RegistrationFormNoFreeEmail (line 119) | class RegistrationFormNoFreeEmail(RegistrationForm):
    method clean_email (line 133) | def clean_email(self):

FILE: dirigible/registration/management/commands/cleanupregistration.py
  class Command (line 15) | class Command(NoArgsCommand):
    method handle_noargs (line 18) | def handle_noargs(self, **options):

FILE: dirigible/registration/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: dirigible/registration/models.py
  class RegistrationManager (line 17) | class RegistrationManager(models.Manager):
    method activate_user (line 26) | def activate_user(self, activation_key):
    method create_inactive_user (line 62) | def create_inactive_user(self, username, password, email,
    method create_profile (line 130) | def create_profile(self, user):
    method delete_expired_users (line 145) | def delete_expired_users(self):
  class RegistrationProfile (line 192) | class RegistrationProfile(models.Model):
    class Meta (line 218) | class Meta:
    method __unicode__ (line 222) | def __unicode__(self):
    method activation_key_expired (line 225) | def activation_key_expired(self):

FILE: dirigible/registration/tests.py
  class RegistrationTestCase (line 37) | class RegistrationTestCase(TestCase):
    method setUp (line 44) | def setUp(self):
  class RegistrationModelTests (line 55) | class RegistrationModelTests(RegistrationTestCase):
    method test_new_user_is_inactive (line 61) | def test_new_user_is_inactive(self):
    method test_registration_profile_created (line 68) | def test_registration_profile_created(self):
    method test_activation_email (line 75) | def test_activation_email(self):
    method test_activation (line 82) | def test_activation(self):
    method test_account_expiration_condition (line 109) | def test_account_expiration_condition(self):
    method test_expired_user_deletion (line 126) | def test_expired_user_deletion(self):
    method test_management_command (line 136) | def test_management_command(self):
  class RegistrationFormTests (line 146) | class RegistrationFormTests(RegistrationTestCase):
    method test_registration_form (line 152) | def test_registration_form(self):
    method test_registration_form_tos (line 202) | def test_registration_form_tos(self):
    method test_registration_form_unique_email (line 222) | def test_registration_form_unique_email(self):
    method test_registration_form_no_free_email (line 241) | def test_registration_form_no_free_email(self):
  class RegistrationViewTests (line 264) | class RegistrationViewTests(RegistrationTestCase):
    method test_registration_view (line 269) | def test_registration_view(self):
    method test_activation_view (line 294) | def test_activation_view(self):

FILE: dirigible/registration/views.py
  function activate (line 17) | def activate(request, activation_key,
  function register (line 76) | def register(request, success_url=None,

FILE: dirigible/shared/static/ace/ace-uncompressed.js
  function SelectionType (line 1082) | function SelectionType(typeSpec) {
  function DeferredType (line 1199) | function DeferredType(typeSpec) {
  function ArrayType (line 1239) | function ArrayType(typeSpec) {
  function Conversion (line 1396) | function Conversion(value, status, message, predictions) {
  function Type (line 1434) | function Type() {
  function reconstituteType (line 1545) | function reconstituteType(name, typeSpec) {
  function splitSafe (line 1775) | function splitSafe(s, separator, limit, bLowerCase) {
  function parseKeys (line 1781) | function parseKeys(keys, val, ret) {
  function buildKeyHash (line 1806) | function buildKeyHash(command) {
  function findKeyCommand (line 1855) | function findKeyCommand(env, sender, hashId, textOrKey) {
  function execKeyCommand (line 1873) | function execKeyCommand(env, sender, hashId, textOrKey) {
  function addCommand (line 1893) | function addCommand(command) {
  function upgradeType (line 1920) | function upgradeType(name, param) {
  function removeCommand (line 1929) | function removeCommand(command) {
  function getCommand (line 1935) | function getCommand(name) {
  function getCommandNames (line 1939) | function getCommandNames() {
  function defaultArgsProvider (line 1947) | function defaultArgsProvider(request, callback) {
  function exec (line 1992) | function exec(command, env, sender, args, typed) {
  function Request (line 2107) | function Request(options) {
  function stringifyArguments (line 2465) | function stringifyArguments(args) {
  function NameGuesser (line 2551) | function NameGuesser() {
  function Setting (line 3541) | function Setting(settingSpec, settings) {
  function Settings (line 3614) | function Settings(persister) {
  function CookiePersister (line 3764) | function CookiePersister() {
  function create (line 4721) | function create() {
  function onMouseMove (line 5982) | function onMouseMove(e) {
  function onReleaseCapture (line 5987) | function onReleaseCapture(e) {
  function onMouseMove (line 6006) | function onMouseMove(e) {
  function onMouseUp (line 6011) | function onMouseUp(e) {
  function normalizeCommandKeys (line 6082) | function normalizeCommandKeys(callback, e, keyCode) {
  function sendText (line 6510) | function sendText(valueToSend) {
  function onStartSelect (line 6907) | function onStartSelect(pos) {
  function bindKey (line 7145) | function bindKey(win, mac) {
  function addSplit (line 8356) | function addSplit(screenPos) {
  function getLine (line 10524) | function getLine(row) {
  function afterLoad (line 11917) | function afterLoad(theme) {
  function addToken (line 12552) | function addToken(token, value) {

FILE: dirigible/shared/static/ace/ace.js
  function m (line 1) | function m(a){if(a instanceof e)this.subtype=a;else{if(typeof a!=="strin...
  function l (line 1) | function l(a){if(typeof a.defer!=="function")throw new Error("Instances ...
  function j (line 1) | function j(a){if(!Array.isArray(a.data)&&typeof a.data!=="function")thro...
  function i (line 1) | function i(a,b){if(a.substr(-2)==="[]"){var c=a.slice(0,-2);return new g...
  function f (line 1) | function f(){}
  function e (line 1) | function e(a,b,c,e){this.value=a,this.status=b||d.VALID,this.message=c,t...
  function J (line 1) | function J(a){a=a||{},this.command=a.command,this.args=a.args,this.typed...
  function G (line 1) | function G(a,b,c,e,f){function h(){a.exec(b,g.args,g),!g.isAsync&&!g.isD...
  function F (line 1) | function F(a,b){var c=a.args,d=a.command.params;for(var e=0;e<d.length;e...
  function E (line 1) | function E(){return z}
  function D (line 1) | function D(a){return q[a]}
  function C (line 1) | function C(a){var b=typeof a==="string"?a:a.name;delete q[b],n.arrayRemo...
  function B (line 1) | function B(a,b){var c=b.type;b.type=m.getType(c);if(b.type==null)throw n...
  function A (line 1) | function A(a){if(!a.name)throw new Error("All registered commands must h...
  function y (line 1) | function y(a,b,c,d){var e=x(a,b,c,d);return e?G(e,a,b,{}):!1}
  function x (line 1) | function x(a,b,c,d){j.isNumber(d)&&(d=h.keyCodeToString(d));var e=(s[c]|...
  function w (line 1) | function w(a){var b=a.bindKey,c=b[v],d=r,e=s;if(!b.sender)throw new Erro...
  function u (line 1) | function u(a,b,c){var d,e=0,f=t(a,"\\-",null,!0),g=0,i=f.length;for(;g<i...
  function t (line 1) | function t(a,b,c,d){return(d&&a.toLowerCase()||a).replace(/(?:^\s+|\n|\s...
  function i (line 1) | function i(){}
  function g (line 1) | function g(a){for(var b=0;b<a.length;++b){var c=a[b];typeof c=="object"?...
  function n (line 1) | function n(){}
  function k (line 1) | function k(a){this._deactivated={},this._settings={},this._settingNames=...
  function j (line 1) | function j(a,b){this._settings=b,Object.keys(a).forEach(function(b){this...
  function e (line 1) | function e(){return{settings:d}}
  function g (line 1) | function g(a,b,c){var f=0;e.isOpera&&e.isMac?f=0|(b.metaKey?1:0)|(b.altK...
  function f (line 1) | function f(e){c&&c(e),d&&d(),b.removeListener(a,"mousemove",c),b.removeL...
  function e (line 1) | function e(a){c(a);return b.stopPropagation(a)}
  function e (line 1) | function e(a){b&&b(a),c&&c(),document.removeEventListener("mousemove",d,...
  function d (line 1) | function d(a){b(a),a.stopPropagation()}
  function k (line 1) | function k(a){if(!i){var d=a||c.value;d&&(d.charCodeAt(d.length-1)==g.ch...
  function C (line 1) | function C(b){a.shiftKey?l.selection.selectToPosition(b):m.$clickSelecti...
  function f (line 1) | function f(a,b){return{win:a,mac:b,sender:"editor"}}
  function j (line 1) | function j(a){var b=e.slice(h,a),f=b.length;b.join("").replace(/4/g,func...
  function k (line 1) | function k(e){var f=a.getLine(e);b&&e==c.end.row&&(f=f.substring(0,c.end...
  function d (line 1) | function d(a){c.$theme&&e.removeCssClass(c.container,c.$theme),c.$theme=...
  function i (line 1) | function i(b,c){var d=c.replace(/&/g,"&amp;").replace(/</g,"&lt;").repla...

FILE: dirigible/shared/static/ace/cockpit-uncompressed.js
  function Hint (line 123) | function Hint(status, message, start, end, predictions) {
  function ConversionHint (line 188) | function ConversionHint(conversion, arg) {
  function Argument (line 222) | function Argument(emitter, text, start, end, prefix, suffix) {
  function Assignment (line 310) | function Assignment(param, requisition) {
  function Requisition (line 607) | function Requisition(env) {
  function CliRequisition (line 816) | function CliRequisition(env, options) {
  function unescape2 (line 977) | function unescape2(str) {
  function CliView (line 1386) | function CliView(cli, env) {
  function hideOutput (line 1480) | function hideOutput() {
  function imageUrl (line 1774) | function imageUrl(path) {
  function RequestView (line 1803) | function RequestView(request, cliView) {
  function Templater (line 1938) | function Templater() {

FILE: dirigible/shared/static/ace/cockpit.js
  function r (line 1) | function r(a,b){q.call(this,a),b&&b.flags&&(this.flags=b.flags)}
  function q (line 1) | function q(a){this.env=a,this.commandAssignment=new o(p,this)}
  function o (line 1) | function o(a,b){this.param=a,this.requisition=b,this.setValue(a.defaultV...
  function n (line 1) | function n(a,b,c,d,e,f){this.emitter=a,this.setText(b),this.start=c,this...
  function m (line 1) | function m(a,b){this.status=a.status,this.message=a.message,b?(this.star...
  function l (line 1) | function l(a,b,c,d,e){this.status=a,this.message=b;if(typeof c==="number...
  function g (line 1) | function g(a){return a.replace(/\uF000/g," ").replace(/\uF001/g,"'").rep...
  function n (line 1) | function n(a,b){a.cliView=this,this.cli=a,this.doc=document,this.win=f.g...
  function d (line 1) | function d(){f.removeCssClass(this.output,"cptFocusPopup"),f.removeCssCl...
  function l (line 1) | function l(a,b){this.request=a,this.cliView=b,this.imageUrl=k,this.rowin...
  function k (line 1) | function k(b){var d;try{d=a("text!cockpit/ui/"+b)}catch(e){}if(d)return ...
  function Templater (line 1) | function Templater(){this.scope=[]}

FILE: dirigible/shared/static/ace/worker-javascript.js
  function initSender (line 1) | function initSender(){var a=require("pilot/event_emitter").EventEmitter,...
  function initBaseUrls (line 1) | function initBaseUrls(a){require.tlns=a}
  function cT (line 1) | function cT(){function b(){var a=K;bI("[");if(K.id!=="]")for(;;){if(K.id...
  function cR (line 1) | function cR(a,b){var c,d=S;S=Object.create(d),v={"(name)":a||'"'+e+'"',"...
  function cQ (line 1) | function cQ(){var a,b=K,c=[];bI("("),bM();if(K.id===")")bI(")"),bM(Q,$);...
  function cP (line 1) | function cP(){var a=cg(!0);a||(K.id==="(string)"?(a=K.value,N.adsafe&&(a...
  function cO (line 1) | function cO(){var a,b,c,d,e,f,g,h=N.white,i;bd="html",be="",U=null;for(;...
  function cN (line 1) | function cN(a){return"</"+a+">"}
  function cM (line 1) | function cM(d,e){var g,h=z[d],i;T=!1,h||bC("Unrecognized tag '<{a}>'.",K...
  function cL (line 1) | function cL(b,c,d){var e,f;c==="id"?(e=typeof d==="string"?d.toUpperCase...
  function cK (line 1) | function cK(a){a!=="html"&&!N.fragment&&(a==="div"&&N.adsafe?bC("ADSAFE:...
  function cJ (line 1) | function cJ(){var a;while(K.id==="@"){a=bH(),bI("@");if(K.identifier)swi...
  function cI (line 1) | function cI(){while(K.id!=="</"&&K.id!=="(end)")cH(),bd="styleproperty",...
  function cH (line 1) | function cH(){K.id==="{"&&bA("Expected a style pattern, and instead saw ...
  function cG (line 1) | function cG(){if(K.identifier)bw(z,N.cap?K.value.toLowerCase():K.value)|...
  function cF (line 1) | function cF(){var a;for(;;){if(K.id==="}"||K.id==="(end)"||be&&K.id===be...
  function cE (line 1) | function cE(){if(K.id==="(number)")bI(),K.value==="n"&&K.identifier&&(bK...
  function cD (line 1) | function cD(a){var b=0,c,d,e,f,g=0,h;switch(typeof a){case"function":ret...
  function cC (line 1) | function cC(){var a;while(K.id==="*"||K.id==="#"||K.value==="_")N.css||b...
  function cB (line 1) | function cB(){var a,b;if(K.identifier&&K.value==="url"){K=bE.range("(","...
  function cA (line 1) | function cA(){var a;if(K.identifier&&K.value==="rect"){bI(),bI("(");for(...
  function cz (line 1) | function cz(){if(K.identifier&&K.value==="counter"){bI(),bI("("),bI(),K....
  function cy (line 1) | function cy(){while(K.id!==";"){!cp()&&!cr()&&bA("Expected a name and in...
  function cx (line 1) | function cx(){if(K.identifier&&K.value==="attr"){bI(),bI("("),K.identifi...
  function cw (line 1) | function cw(){if(!K.identifier)return ct();if(K.value==="auto"){bI();ret...
  function cv (line 1) | function cv(){if(!K.identifier)return ct();switch(K.value){case"thin":ca...
  function cu (line 1) | function cu(){K.id==="-"&&(bI("-"),bK());if(K.type==="(number)"){bI(),K....
  function ct (line 1) | function ct(){K.id==="-"&&(bI("-"),bK(),bQ());if(K.type==="(number)"){bI...
  function cs (line 1) | function cs(){var a,b,c;if(K.identifier){c=K.value;if(c==="rgb"||c==="rg...
  function cr (line 1) | function cr(){if(K.type==="(string)"){bI();return!0}}
  function cq (line 1) | function cq(){K.id==="-"&&(bI("-"),bK(),bQ());if(K.type==="(number)"){bI...
  function cp (line 1) | function cp(){if(K.identifier){bI();return!0}}
  function co (line 1) | function co(a){var b=a.value,c=a.line,d=B[b];typeof d==="function"&&(d=!...
  function cn (line 1) | function cn(a){J&&typeof J[a]!=="boolean"&&bA("Unexpected /*member '{a}'...
  function cm (line 1) | function cm(a,b){var c,d=C,e=D,f=X,g=S,h;C=a,S=Object.create(S),bN($,K),...
  function cl (line 1) | function cl(c){var d=[],e,f;if(N.adsafe)switch(c){case"script":b||(K.val...
  function ck (line 1) | function ck(){if(K.value==="use strict"){X&&bA('Unnecessary "use strict"...
  function cj (line 1) | function cj(a){var b=D,c,d=S,e=K;if(e.id===";")bA("Unnecessary semicolon...
  function ci (line 1) | function ci(a){var b=0,c;if(K.id===";"&&!M)for(;;){c=bH(b);if(c.reach)re...
  function ch (line 1) | function ch(a){var b=cg(a);if(b)return b;$.id==="function"&&K.id==="("?b...
  function cg (line 1) | function cg(a){if(K.identifier){bI(),N.safe&&h[$.value]?bA("ADsafe viola...
  function cf (line 1) | function cf(a,b){var c=bS(a,150);c.led=function(a){N.plusplus?bA("Unexpe...
  function ce (line 1) | function ce(a){bS(a,20).exps=!0;return b_(a,function(a,b){N.bitwise&&bA(...
  function cd (line 1) | function cd(a,b,c){var d=bS(a,c);bW(d),d.led=typeof b==="function"?b:fun...
  function cc (line 1) | function cc(a,b){bS(a,20).exps=!0;return b_(a,function(a,b){var c;b.left...
  function cb (line 1) | function cb(a){return a&&(a.type==="(number)"&&+a.value===0||a.type==="(...
  function ca (line 1) | function ca(a,b){var c=bS(a,100);c.led=function(a){bO(Q,$),bN($,K);var c...
  function b_ (line 1) | function b_(a,b,c,d){var e=bS(a,c);bW(e),e.led=function(a){d||(bO(Q,$),b...
  function b$ (line 1) | function b$(a,b){return bZ(a,function(){typeof b==="function"&&b(this);r...
  function bZ (line 1) | function bZ(a,b){var c=bY(a,b);c.identifier=c.reserved=!0;return c}
  function bY (line 1) | function bY(a,b){var c=bT(a);c.type=a,c.nud=b;return c}
  function bX (line 1) | function bX(a,b){var c=bS(a,150);bW(c),c.nud=typeof b==="function"?b:fun...
  function bW (line 1) | function bW(a){var b=a.id.charAt(0);if(b>="a"&&b<="z"||b>="A"&&b<="Z")a....
  function bV (line 1) | function bV(a,b){var c=bU(a,b);c.block=!0;return c}
  function bU (line 1) | function bU(a,b){var c=bT(a);c.identifier=c.reserved=!0,c.fud=b;return c}
  function bT (line 1) | function bT(a){return bS(a,0)}
  function bS (line 1) | function bS(a,b){var c=Y[a];if(!c||typeof c!=="object")Y[a]=c={id:a,lbp:...
  function bR (line 1) | function bR(){$.line!==K.line?N.laxbreak||bA("Bad line breaking before '...
  function bQ (line 1) | function bQ(a){a=a||$,a.line!==K.line&&bA("Line breaking error '{a}'.",a...
  function bP (line 1) | function bP(a){var b;N.white&&K.id!=="(end)"&&(b=D+(a||0),K.from!==b&&bA...
  function bO (line 1) | function bO(a,b){a=a||$,b=b||K,!N.laxbreak&&a.line!==b.line?bA("Bad line...
  function bN (line 1) | function bN(a,b){N.white&&(a=a||$,b=b||K,a.line===b.line&&a.character===...
  function bM (line 1) | function bM(a,b){a=a||$,b=b||K,N.white&&!a.comment&&a.line===b.line&&bK(...
  function bL (line 1) | function bL(a,b){a=a||$,b=b||K,N.white&&(a.character!==b.from||a.line!==...
  function bK (line 1) | function bK(a,b){a=a||$,b=b||K,(N.white||bd==="styleproperty"||bd==="sty...
  function bJ (line 1) | function bJ(a,b){var c;K.id==="(end)"&&bC("Unexpected early end of progr...
  function bI (line 1) | function bI(a,b){switch($.id){case"(number)":K.id==="."&&bA("A dot follo...
  function bH (line 1) | function bH(a){var b=a||0,c=0,d;while(c<=b)d=H[c],d||(d=H[c]=bE.token())...
  function bG (line 1) | function bG(){var a,b,c,d=K.value,e,f;switch(d){case"*/":bC("Unbegun com...
  function bF (line 1) | function bF(a,b){N.safe&&v["(global)"]&&typeof O[a]!=="boolean"?bA("ADsa...
  function bD (line 1) | function bD(a,b,c,d,e,f,g){return bC(a,{line:b,from:c},d,e,f,g)}
  function bC (line 1) | function bC(a,b,c,d,e,f){var g=bA(a,b,c,d,e,f);bz("Stopping, unable to c...
  function bB (line 1) | function bB(a,b,c,d,e,f,g){return bA(a,{line:b,from:c},d,e,f,g)}
  function bA (line 1) | function bA(a,b,c,e,f,g){var h,i,j;b=b||K,b.id==="(end)"&&(b=$),i=b.line...
  function bz (line 1) | function bz(a,b,c){throw{name:"JSHintError",line:b,character:c,message:a...
  function by (line 1) | function by(){N.safe||(N.couch&&bx(O,k),N.rhino&&bx(O,R),N.node&&bx(O,L)...
  function bx (line 1) | function bx(a,b){var c;for(c in b)bw(b,c)&&(a[c]=b[c])}
  function bw (line 1) | function bw(a,b){return Object.prototype.hasOwnProperty.call(a,b)}
  function bv (line 1) | function bv(){}
  function f (line 1) | function f(d,e){var f,g;d==="(color)"||d==="(range)"?g={type:d}:d==="(pu...
  function e (line 1) | function e(){var b;if(c>=G.length)return!1;a=1,d=G[c],c+=1,b=d.search(/ ...
  function s (line 1) | function s(g){function k(b){var e=parseInt(d.substr(i+1,b),16);i+=b,e>=3...
  function r (line 1) | function r(c){var e=c.exec(d),f;if(e){n=e[0].length,f=e[1],h=f.charAt(0)...
  function o (line 1) | function o(a,b){var c,d,e;if(b){m.push("<div><i>"+a+"</i> "),b=b.sort();...
  function parseStdin (line 1) | function parseStdin(a,b){for(;;)try{var c=new lexer.Tokenizer(a,"stdin",...
  function parse (line 1) | function parse(a,b,c){var d=new lexer.Tokenizer(a,b,c),e=Script(d,!1);if...
  function PrimaryExpression (line 1) | function PrimaryExpression(a,b){var c,d,e=a.get(!0);switch(e){case FUNCT...
  function ArgumentList (line 1) | function ArgumentList(a,b){var c,d;c=new Node(a,{type:LIST});if(a.match(...
  function MemberExpression (line 1) | function MemberExpression(a,b,c){var d,e,f,g;a.match(NEW)?(d=new Node(a)...
  function UnaryExpression (line 1) | function UnaryExpression(a,b){var c,d,e;switch(e=a.get(!0)){case DELETE:...
  function MultiplyExpression (line 1) | function MultiplyExpression(a,b){var c,d;c=UnaryExpression(a,b);while(a....
  function AddExpression (line 1) | function AddExpression(a,b){var c,d;c=MultiplyExpression(a,b);while(a.ma...
  function ShiftExpression (line 1) | function ShiftExpression(a,b){var c,d;c=AddExpression(a,b);while(a.match...
  function RelationalExpression (line 1) | function RelationalExpression(a,b){var c,d,e=b.update({inForLoopInit:!1}...
  function EqualityExpression (line 1) | function EqualityExpression(a,b){var c,d;c=RelationalExpression(a,b);whi...
  function BitwiseAndExpression (line 1) | function BitwiseAndExpression(a,b){var c,d;c=EqualityExpression(a,b);whi...
  function BitwiseXorExpression (line 1) | function BitwiseXorExpression(a,b){var c,d;c=BitwiseAndExpression(a,b);w...
  function BitwiseOrExpression (line 1) | function BitwiseOrExpression(a,b){var c,d;c=BitwiseXorExpression(a,b);wh...
  function AndExpression (line 1) | function AndExpression(a,b){var c,d;c=BitwiseOrExpression(a,b);while(a.m...
  function OrExpression (line 1) | function OrExpression(a,b){var c,d;c=AndExpression(a,b);while(a.match(OR...
  function ConditionalExpression (line 1) | function ConditionalExpression(a,b){var c,d;c=OrExpression(a,b);if(a.mat...
  function AssignExpression (line 1) | function AssignExpression(a,b){var c,d;if(a.match(YIELD,!0))return Retur...
  function Expression (line 1) | function Expression(a,b){var c,d;c=AssignExpression(a,b);if(a.match(COMM...
  function ParenExpression (line 1) | function ParenExpression(a,b){var c=Expression(a,b.update({inForLoopInit...
  function HeadExpression (line 1) | function HeadExpression(a,b){var c=MaybeLeftParen(a,b),d=ParenExpression...
  function ComprehensionTail (line 1) | function ComprehensionTail(a,b){var c,d,e,f,g;c=new Node(a,{type:COMP_TA...
  function GeneratorExpression (line 1) | function GeneratorExpression(a,b,c){return new Node(a,{type:GENERATOR,ex...
  function DestructuringExpression (line 1) | function DestructuringExpression(a,b,c){var d=PrimaryExpression(a,b);d.d...
  function checkDestructuring (line 1) | function checkDestructuring(a,b,c,d){if(c.type===ARRAY_COMP)throw a.newS...
  function LetBlock (line 1) | function LetBlock(a,b,c){var d,e;d=new Node(a,{type:LET_BLOCK,varDecls:[...
  function Variables (line 1) | function Variables(a,b,c){var d,e,f,g,h,i;i=a.token.type;switch(i){case ...
  function FunctionDefinition (line 1) | function FunctionDefinition(a,b,c,d){var e,f=new Node(a,{params:[]});f.t...
  function ReturnOrYield (line 1) | function ReturnOrYield(a,b){var c,d,e=a.token.type,f,g=b.parentScript;if...
  function MagicalSemicolon (line 1) | function MagicalSemicolon(a){var b;if(a.lineno===a.token.lineno){b=a.pee...
  function Statement (line 1) | function Statement(a,b){var c,d,e,f,g,h,i,j=a.get(!0),k,l,m;switch(j){ca...
  function Block (line 1) | function Block(a,b){a.mustMatch(LEFT_CURLY);var c=new Node(a,blockInit()...
  function Statements (line 1) | function Statements(a,b,c){try{while(!a.done&&a.peek(!0)!==RIGHT_CURLY)c...
  function MaybeRightParen (line 1) | function MaybeRightParen(a,b){b===LEFT_PAREN&&a.mustMatch(RIGHT_PAREN)}
  function MaybeLeftParen (line 1) | function MaybeLeftParen(a,b){if(b.parenFreeMode)return a.match(LEFT_PARE...
  function scriptInit (line 1) | function scriptInit(){return{type:SCRIPT,funDecls:[],varDecls:[],modDecl...
  function blockInit (line 1) | function blockInit(){return{type:BLOCK,varDecls:[]}}
  function tokenString (line 1) | function tokenString(a){var b=definitions.tokens[a];return/^\W/.test(b)?...
  function Node (line 1) | function Node(a,b){var c=a.token;c?(this.type=c.type,this.value=c.value,...
  function Script (line 1) | function Script(a,b){var c=new Node(a,scriptInit()),d=new StaticContext(...
  function StaticContext (line 1) | function StaticContext(a,b,c,d,e){this.parentScript=a,this.parentBlock=b...
  function pushDestructuringVarDecls (line 1) | function pushDestructuringVarDecls(a,b){for(var c in a){var d=a[c];d.typ...
  function Tokenizer (line 1) | function Tokenizer(a,b,c){this.cursor=0,this.source=String(a),this.token...
  method done (line 1) | get done(){return this.peek(!0)===END}
  method token (line 1) | get token(){return this.tokens[this.tokenIndex]}
  function y (line 1) | function y(a){this.elts=a||null}
  function x (line 1) | function x(){this.table=Object.create(null,{}),this.size=0}
  function v (line 1) | function v(){return undefined}
  function u (line 1) | function u(a){return{getOwnPropertyDescriptor:function(b){var c=Object.g...
  function t (line 1) | function t(a){var b={};for(var c in Object.getOwnPropertyNames(a))b[c]=O...
  function s (line 1) | function s(a,b){while(a){if(({}).hasOwnProperty.call(a,b))return Object....
  function r (line 1) | function r(a){return typeof a==="function"&&a.toString().match(/\[native...
  function q (line 1) | function q(a,b,c,d,e,f){Object.defineProperty(a,b,{value:c,writable:!e,c...
  function p (line 1) | function p(a,b,c,d,e){Object.defineProperty(a,b,{get:c,configurable:!d,e...

FILE: dirigible/shared/static/dirigible/scripts/cell_editor.js
  function CellEditorFactory (line 109) | function CellEditorFactory(currying_formula_bar) {

FILE: dirigible/shared/static/dirigible/scripts/console_view.js
  function ConsoleView (line 12) | function ConsoleView($consoleDiv) {

FILE: dirigible/shared/static/dirigible/scripts/dialogs.js
  function Initialise (line 10) | function Initialise(grid, urls) {

FILE: dirigible/shared/static/dirigible/scripts/editor_commands.js
  function EditorCommands (line 14) | function EditorCommands(urls, editor) {

FILE: dirigible/shared/static/dirigible/scripts/feedback_dialog.js
  function Initialise (line 10) | function Initialise(urls, username) {

FILE: dirigible/shared/static/dirigible/scripts/grid_commands.js
  function GridCommands (line 15) | function GridCommands(urls, grid) {

FILE: dirigible/shared/static/dirigible/scripts/grid_content_converter.js
  function getGridCellFormula (line 5) | function getGridCellFormula(grid, slickCellLocation) {
  function slickGridCellDataToPostParams (line 18) | function slickGridCellDataToPostParams(grid, slickCellLocation) {

FILE: dirigible/shared/static/dirigible/scripts/grid_interaction_handler.js
  function GridInteractionHandler (line 9) | function GridInteractionHandler($, grid, gridCommands, gridRemoteModel) {

FILE: dirigible/shared/static/dirigible/scripts/grid_remote_model.js
  function GridRemoteModel (line 8) | function GridRemoteModel(urls) {

FILE: dirigible/shared/static/dirigible/scripts/grid_view.js
  function GridView (line 15) | function GridView(grid, remoteModel) {

FILE: dirigible/shared/static/dirigible/scripts/htmlescape.js
  function htmlescape (line 5) | function htmlescape(untrusted_string) {

FILE: dirigible/shared/static/dirigible/scripts/keyboard_cellrange_selector.js
  function KeyboardCellRangeSelector (line 17) | function KeyboardCellRangeSelector() {

FILE: dirigible/shared/static/dirigible/scripts/page_commands.js
  function PageCommands (line 14) | function PageCommands(gridCommands, editorCommands) {

FILE: dirigible/shared/static/dirigible/scripts/page_interaction_handler.js
  function PageInteractionHandler (line 12) | function PageInteractionHandler(

FILE: dirigible/shared/static/dirigible/scripts/page_view.js
  function PageView (line 12) | function PageView(username, consoleView, usercodeView, gridView) {

FILE: dirigible/shared/static/dirigible/scripts/security_settings.js
  function Model (line 16) | function Model($, urls) {
  function Dialog (line 84) | function Dialog($, urls) {

FILE: dirigible/shared/static/dirigible/scripts/selection_model.js
  function SelectionModel (line 15) | function SelectionModel() {

FILE: dirigible/shared/static/dirigible/scripts/sheet_page_utils.js
  function InitialiseSheetUtils (line 12) | function InitialiseSheetUtils(urls, pageView) {

FILE: dirigible/shared/static/dirigible/scripts/toolbar_interaction_handler.js
  function ToolbarInteractionHandler (line 9) | function ToolbarInteractionHandler(gridCommands, pageCommands) {

FILE: dirigible/shared/static/dirigible/scripts/usercode_view.js
  function UsercodeView (line 12) | function UsercodeView(editor) {

FILE: dirigible/shared/static/dirigible/tests/jsmock.js
  function MockControl (line 42) | function MockControl() {
  function ExpectationMatcher (line 167) | function ExpectationMatcher() {
  function InvocationBehavior (line 245) | function InvocationBehavior(caller, method, methodArguments) {
  function TypeOf (line 251) | function TypeOf(type) {
  function Discrepancy (line 304) | function Discrepancy(message, behavior) {

FILE: dirigible/shared/static/dirigible/tests/test_utils.js
  function elementVisible (line 6) | function elementVisible(element, expected, message) {
  function assertDeepAreSame (line 20) | function assertDeepAreSame(expected, actual, message) {
  function _deepAreSame (line 35) | function _deepAreSame(expected, actual, message) {

FILE: dirigible/shared/static/dirigible/tests/yuirunner.js
  function escape_quotes (line 2) | function escape_quotes(key, value) {

FILE: dirigible/shared/static/dirigible/tests/yuitest/yuitest-combo.js
  function G (line 9) | function G(y,z){return z.toUpperCase();}
  function H (line 14) | function H(O,N){if(!I.shift){I.shift=false;}if(!I.alt){I.alt=false;}if(!...
  function B (line 20) | function B(I,H){I=G.createElement(I);if(H){for(var J in H){if(H.hasOwnPr...
  function F (line 20) | function F(I,H){this._sName=F._index;F._index++;this._init.apply(this,ar...
  function B (line 28) | function B(C){this.testObject=C;this.firstChild=null;this.lastChild=null...
  function A (line 28) | function A(){A.superclass.constructor.apply(this,arguments);this.masterS...
  function B (line 31) | function B(C){return C<10?"0"+C:C;}

FILE: dirigible/shared/static/json/json2.js
  function f (line 168) | function f(n) {
  function quote (line 209) | function quote(string) {
  function str (line 227) | function str(key, holder) {
  function walk (line 410) | function walk(holder, key) {

FILE: dirigible/shared/static/slickgrid/slick.cellrangedecorator.js
  function CellRangeDecorator (line 20) | function CellRangeDecorator(grid, options) {

FILE: dirigible/shared/static/slickgrid/slick.cellrangeselector.js
  function CellRangeSelector (line 10) | function CellRangeSelector(options) {

FILE: dirigible/shared/static/slickgrid/slick.cellselectionmodel.js
  function CellSelectionModel (line 10) | function CellSelectionModel(options) {

FILE: dirigible/shared/static/slickgrid/slick.core.js
  function EventData (line 35) | function EventData() {
  function Event (line 79) | function Event() {
  function Range (line 141) | function Range(fromRow, fromCell, toRow, toCell) {
  function NonDataItem (line 222) | function NonDataItem() {
  function Group (line 233) | function Group() {
  function GroupTotals (line 296) | function GroupTotals() {
  function EditorLock (line 317) | function EditorLock() {

FILE: dirigible/shared/static/slickgrid/slick.editors.js
  function toggle (line 450) | function toggle(e) {

FILE: dirigible/shared/static/slickgrid/slick.grid.js
  function SlickGrid (line 49) | function SlickGrid(container,data,columns,options) {

FILE: dirigible/shared/static/splitter/splitter.js
  function startSplitMouse (line 39) | function startSplitMouse(evt) {
  function doSplitMouse (line 49) | function doSplitMouse(evt) {
  function endSplitMouse (line 57) | function endSplitMouse(evt) {
  function resplit (line 69) | function resplit(newPos) {
  function dimSum (line 83) | function dimSum(jq, dims) {

FILE: dirigible/shared/tests/test_views.py
  class TestRedirectTo (line 15) | class TestRedirectTo(unittest.TestCase):
    method test_redirect_to_no_params (line 17) | def test_redirect_to_no_params(self):
    method test_redirect_to_with_params (line 26) | def test_redirect_to_with_params(self):

FILE: dirigible/shared/views.py
  function redirect_to (line 10) | def redirect_to(request, url):

FILE: dirigible/sheet/admin.py
  class SheetAdmin (line 8) | class SheetAdmin(admin.ModelAdmin):

FILE: dirigible/sheet/calculate.py
  function is_nan (line 36) | def is_nan(value):
  class MyStdout (line 40) | class MyStdout(object):
    method write (line 41) | def write(self, text):
    method __init__ (line 44) | def __init__(self, worksheet):
  function load_constants (line 48) | def load_constants(worksheet):
  function set_cell_error_and_add_to_console (line 57) | def set_cell_error_and_add_to_console(worksheet, location, exception):
  function recalculate_cell (line 70) | def recalculate_cell(location, leaf_queue, graph, context):
  function create_cell_recalculator (line 84) | def create_cell_recalculator(leaf_queue, unrecalculated_queue, graph, co...
  function evaluate_formulae_in_context (line 100) | def evaluate_formulae_in_context(worksheet, context):
  function execute_usercode (line 118) | def execute_usercode(usercode, context):
  function calculate_with_timeout (line 122) | def calculate_with_timeout(worksheet, usercode, timeout_seconds, private...
  function calculate (line 131) | def calculate(worksheet, usercode, private_key):
  function _calculate (line 138) | def _calculate(worksheet, usercode, private_key):
  function format_traceback (line 176) | def format_traceback(frames):
  function _raise (line 207) | def _raise(exc):
  function run_worksheet (line 211) | def run_worksheet(worksheet_url, overrides, private_key):
  function api_json_to_worksheet (line 226) | def api_json_to_worksheet(sheet_json):

FILE: dirigible/sheet/cell.py
  class Undefined (line 13) | class Undefined(object):
    method __repr__ (line 15) | def __repr__(self):
  class Cell (line 22) | class Cell(object):
    method __init__ (line 24) | def __init__(self):
    method _set_formula (line 28) | def _set_formula(self, value):
    method _get_formula (line 45) | def _get_formula(self):
    method _set_python_formula (line 51) | def _set_python_formula(self, value):
    method _get_python_formula (line 57) | def _get_python_formula(self):
    method _set_value (line 63) | def _set_value(self, value):
    method _get_value (line 70) | def _get_value(self):
    method clear_value (line 75) | def clear_value(self):
    method _set_formatted_value (line 79) | def _set_formatted_value(self, value):
    method _get_formatted_value (line 87) | def _get_formatted_value(self):
    method clear (line 93) | def clear(self):
    method __repr__ (line 102) | def __repr__(self):
    method __eq__ (line 110) | def __eq__(self, other):
    method __ne__ (line 120) | def __ne__(self, other):

FILE: dirigible/sheet/cell_range.py
  class CellRange (line 9) | class CellRange(object):
    method __init__ (line 11) | def __init__(self, worksheet, start, end):
    method __repr__ (line 17) | def __repr__(self):
    method __eq__ (line 25) | def __eq__(self, other):
    method __ne__ (line 36) | def __ne__(self, other):
    method __len__ (line 40) | def __len__(self):
    method locations (line 45) | def locations(self):
    method __iter__ (line 51) | def __iter__(self):
    method cells (line 57) | def cells(self):
    method locations_and_cells (line 63) | def locations_and_cells(self):
    method _location_in_worksheet (line 68) | def _location_in_worksheet(self, location):
    method __getitem__ (line 82) | def __getitem__(self, location):
    method __setitem__ (line 86) | def __setitem__(self, location, value):
    method clear (line 90) | def clear(self):

FILE: dirigible/sheet/clipboard.py
  class Clipboard (line 22) | class Clipboard(models.Model):
    method source_range (line 33) | def source_range(self):
    method width (line 40) | def width(self):
    method height (line 44) | def height(self):
    method copy (line 48) | def copy(self, sheet, start, end):
    method cut (line 76) | def cut(self, sheet, start, end):
    method _get_offset (line 88) | def _get_offset(self, col, row, start_col, start_row):
    method to_cells (line 96) | def to_cells(self, start, end):
    method paste_to (line 121) | def paste_to(self, to_sheet, start, end):

FILE: dirigible/sheet/dependency_graph.py
  class Node (line 10) | class Node(object):
    method __init__ (line 11) | def __init__(self, location, children=None, parents=None):
    method __eq__ (line 17) | def __eq__(self, other):
    method __ne__ (line 24) | def __ne__(self, other):
    method __repr__ (line 27) | def __repr__(self):
    method remove_from_parents (line 33) | def remove_from_parents(self, parent_nodes, leaf_queue):
  function build_dependency_graph (line 44) | def build_dependency_graph(worksheet):
  function _generate_cell_subgraph (line 61) | def _generate_cell_subgraph(worksheet, graph, loc, completed, path):
  function _add_location_dependencies (line 99) | def _add_location_dependencies(graph, location, dependencies):

FILE: dirigible/sheet/dirigible_datetime.py
  class DateTime (line 6) | class DateTime(datetime.datetime):

FILE: dirigible/sheet/errors.py
  class CycleError (line 9) | class CycleError(Exception):
    method __init__ (line 11) | def __init__(self, path):
    method __str__ (line 15) | def __str__(self):
    method __repr__ (line 19) | def __repr__(self):
    method __eq__ (line 23) | def __eq__(self, other):
    method __ne__ (line 29) | def __ne__(self, other):
  function report_cell_error (line 33) | def report_cell_error(worksheet, loc, exc):

FILE: dirigible/sheet/eval_constant.py
  function eval_constant (line 6) | def eval_constant(constant):

FILE: dirigible/sheet/forms.py
  class ImportCSVForm (line 7) | class ImportCSVForm(forms.Form):
    method __init__ (line 8) | def __init__(self, *args, **kwargs):

FILE: dirigible/sheet/formula_interpreter.py
  function transform_arrow (line 17) | def transform_arrow(child):
  function rewrite_cell_reference_as_tuple (line 24) | def rewrite_cell_reference_as_tuple(cell_reference_node):
  function rewrite_cell_reference (line 40) | def rewrite_cell_reference(cell_reference_node):
  function rewrite_cell_range (line 57) | def rewrite_cell_range(node):
  function rewrite (line 84) | def rewrite(parse_node):
  function get_python_formula_from_parse_tree (line 104) | def get_python_formula_from_parse_tree(parse_node):
  function get_dependencies_from_parse_tree (line 108) | def get_dependencies_from_parse_tree(parse_node):

FILE: dirigible/sheet/importer.py
  class DirigibleImportError (line 13) | class DirigibleImportError(Exception):
  function worksheet_from_csv (line 17) | def worksheet_from_csv(
  function worksheet_from_excel (line 68) | def worksheet_from_excel(excel_sheet):

FILE: dirigible/sheet/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: dirigible/sheet/models.py
  function copy_sheet_to_user (line 11) | def copy_sheet_to_user(sheet, user):

FILE: dirigible/sheet/parser/__init__.py
  class FormulaError (line 1) | class FormulaError(Exception):

FILE: dirigible/sheet/parser/fl_cell_range_parse_node.py
  class FLCellRangeParseNode (line 7) | class FLCellRangeParseNode(ParseNode):
    method __init__ (line 9) | def __init__(self, children):
    method __get_first_cell_reference (line 13) | def __get_first_cell_reference(self):
    method __set_first_cell_reference (line 15) | def __set_first_cell_reference(self, cellRef):
    method __get_second_cell_reference (line 20) | def __get_second_cell_reference(self):
    method __set_second_cell_reference (line 23) | def __set_second_cell_reference(self, cellRef):
    method colon (line 29) | def colon(self):

FILE: dirigible/sheet/parser/fl_cell_reference_parse_node.py
  class FLCellReferenceParseNode (line 9) | class FLCellReferenceParseNode(FLReferenceParseNode):
    method __init__ (line 11) | def __init__(self, children):
    method colAbsolute (line 16) | def colAbsolute(self):
    method rowAbsolute (line 21) | def rowAbsolute(self):
    method plainCellName (line 26) | def plainCellName(self):
    method __getLocalReference (line 30) | def __getLocalReference(self):
    method __setLocalReference (line 33) | def __setLocalReference(self, cellRef):
    method coords (line 40) | def coords(self):
    method offset (line 44) | def offset(self, dx, dy, move_absolute=False):
    method canonicalise (line 59) | def canonicalise(self, wsNames):

FILE: dirigible/sheet/parser/fl_column_reference_parse_node.py
  class FLColumnReferenceParseNode (line 10) | class FLColumnReferenceParseNode(FLReferenceParseNode):
    method __init__ (line 12) | def __init__(self, children):
    method isAbsolute (line 17) | def isAbsolute(self):
    method __getPlainColumnName (line 21) | def __getPlainColumnName(self):
    method __setPlainColumnName (line 23) | def __setPlainColumnName(self, newName):
    method colIndex (line 29) | def colIndex(self):
    method coords (line 33) | def coords(self):
    method offset (line 37) | def offset(self, count, _, moveAbsolute=False):
    method __getLocalReference (line 46) | def __getLocalReference(self):
    method __setLocalReference (line 48) | def __setLocalReference(self, newCol):
    method canonicalise (line 54) | def canonicalise(self, wsNames):

FILE: dirigible/sheet/parser/fl_named_column_reference_parse_node.py
  class FLNamedColumnReferenceParseNode (line 9) | class FLNamedColumnReferenceParseNode(FLReferenceParseNode):
    method __init__ (line 11) | def __init__(self, children):
    method header (line 16) | def header(self):

FILE: dirigible/sheet/parser/fl_named_row_reference_parse_node.py
  class FLNamedRowReferenceParseNode (line 9) | class FLNamedRowReferenceParseNode(FLReferenceParseNode):
    method __init__ (line 11) | def __init__(self, children):
    method header (line 16) | def header(self):

FILE: dirigible/sheet/parser/fl_reference_parse_node.py
  function quote_fl_worksheet_name (line 11) | def quote_fl_worksheet_name(name):
  function unquote_fl_worksheet_name (line 17) | def unquote_fl_worksheet_name(name):
  class FLReferenceParseNode (line 24) | class FLReferenceParseNode(ParseNode):
    method __init__ (line 26) | def __init__(self, nodeType, children):
    method whitespace (line 32) | def whitespace(self):
    method __getWorksheet (line 36) | def __getWorksheet(self):
    method __setWorksheet (line 41) | def __setWorksheet(self, ws):
    method canonicalise (line 55) | def canonicalise(self, wsNames):

FILE: dirigible/sheet/parser/fl_row_reference_parse_node.py
  class FLRowReferenceParseNode (line 8) | class FLRowReferenceParseNode(FLReferenceParseNode):
    method __init__ (line 10) | def __init__(self, children):
    method isAbsolute (line 14) | def isAbsolute(self):
    method __getPlainRowName (line 17) | def __getPlainRowName(self):
    method __setPlainRowName (line 19) | def __setPlainRowName(self, newName):
    method rowIndex (line 24) | def rowIndex(self):
    method coords (line 29) | def coords(self):
    method offset (line 33) | def offset(self, _, count, moveAbsolute=False):
    method __getLocalReference (line 43) | def __getLocalReference(self):
    method __setLocalReference (line 45) | def __setLocalReference(self, newRow):

FILE: dirigible/sheet/parser/grammar.py
  function p__root (line 72) | def p__root(p):
  function p_varargslist (line 83) | def p_varargslist(p):
  function p__partial_varargslist_starting_with_doublestar (line 91) | def p__partial_varargslist_starting_with_doublestar(p):
  function p__partial_varargslist_starting_with_star (line 96) | def p__partial_varargslist_starting_with_star(p):
  function p__partial_varargslist_starting_with_keyword (line 105) | def p__partial_varargslist_starting_with_keyword(p):
  function p__partial_varargslist_starting_with_fpdef (line 116) | def p__partial_varargslist_starting_with_fpdef(p):
  function p_fpdef (line 129) | def p_fpdef(p):
  function p_fplist (line 136) | def p_fplist(p):
  function p__comma_fpdefs (line 152) | def p__comma_fpdefs(p):
  function p_test (line 161) | def p_test(p):
  function p__or_and_tests (line 171) | def p__or_and_tests(p):
  function p_and_test (line 180) | def p_and_test(p):
  function p__and_not_tests (line 189) | def p__and_not_tests(p):
  function p_not_test (line 198) | def p_not_test(p):
  function p_comparison (line 207) | def p_comparison(p):
  function p__comp_operator_exprs (line 216) | def p__comp_operator_exprs(p):
  function p_comp_operator (line 225) | def p_comp_operator(p):
  function p_expr (line 244) | def p_expr(p):
  function p__or_concat_exprs (line 253) | def p__or_concat_exprs(p):
  function p_concat_expr (line 262) | def p_concat_expr(p):
  function p__ampersand_shift_exprs (line 271) | def p__ampersand_shift_exprs(p):
  function p_shift_expr (line 280) | def p_shift_expr(p):
  function p__shift_op_arith_exprs (line 289) | def p__shift_op_arith_exprs(p):
  function p_arith_expr (line 300) | def p_arith_expr(p):
  function p__a_op_terms (line 309) | def p__a_op_terms(p):
  function p_term (line 320) | def p_term(p):
  function p__m_op_factors (line 329) | def p__m_op_factors(p):
  function p_percent (line 343) | def p_percent(p):
  function p_factor (line 351) | def p_factor(p):
  function p_power (line 359) | def p_power(p):
  function p_atom (line 369) | def p_atom(p):
  function p_listmaker (line 383) | def p_listmaker(p):
  function p_testlist_gexp (line 392) | def p_testlist_gexp(p):
  function p_lambdef (line 401) | def p_lambdef(p):
  function p_trailer (line 407) | def p_trailer(p):
  function p__trailers (line 424) | def p__trailers(p):
  function p_subscriptlist (line 433) | def p_subscriptlist(p):
  function p__comma_subscripts (line 449) | def p__comma_subscripts(p):
  function p_subscript (line 458) | def p_subscript(p):
  function p__simple_subscript (line 464) | def p__simple_subscript(p):
  function p__complex_subscript (line 470) | def p__complex_subscript(p):
  function p__short_slice (line 479) | def p__short_slice(p):
  function p__lower_bound (line 487) | def p__lower_bound(p):
  function p__upper_bound (line 492) | def p__upper_bound(p):
  function p_sliceop (line 497) | def p_sliceop(p):
  function p_exprlist (line 503) | def p_exprlist(p):
  function p__comma_exprs (line 519) | def p__comma_exprs(p):
  function p_testlist (line 528) | def p_testlist(p):
  function p__comma_tests (line 544) | def p__comma_tests(p):
  function p_testlist_safe (line 553) | def p_testlist_safe(p):
  function p_dictmaker (line 565) | def p_dictmaker(p):
  function p__key_value_pair (line 581) | def p__key_value_pair(p):
  function p__comma_key_value_pairs (line 586) | def p__comma_key_value_pairs(p):
  function p_arglist (line 595) | def p_arglist(p):
  function p__partial_arglist_starting_with_doublestar (line 603) | def p__partial_arglist_starting_with_doublestar(p):
  function p__partial_arglist_starting_with_star (line 608) | def p__partial_arglist_starting_with_star(p):
  function p__partial_arglist_starting_with_keyword (line 617) | def p__partial_arglist_starting_with_keyword(p):
  function p__partial_arglist_starting_with_argument (line 628) | def p__partial_arglist_starting_with_argument(p):
  function p_argument (line 651) | def p_argument(p):
  function p__keyword_argument (line 657) | def p__keyword_argument(p):
  function p_list_iter (line 662) | def p_list_iter(p):
  function p_list_for (line 668) | def p_list_for(p):
  function p_list_if (line 674) | def p_list_if(p):
  function p_gen_iter (line 680) | def p_gen_iter(p):
  function p_gen_for (line 686) | def p_gen_for(p):
  function p_gen_if (line 692) | def p_gen_if(p):
  function p_testlist1 (line 698) | def p_testlist1(p):
  function p__name (line 707) | def p__name(p):
  function p__number (line 712) | def p__number(p):
  function p__imaginary (line 719) | def p__imaginary(p):
  function p__float (line 724) | def p__float(p):
  function p__integer (line 729) | def p__integer(p):
  function p_stringliteral (line 736) | def p_stringliteral(p):
  function p__shortstring (line 747) | def p__shortstring(p):
  function p__longstring (line 753) | def p__longstring(p):
  function FixFunction (line 761) | def FixFunction(p):
  function p_iserror_function (line 764) | def p_iserror_function(p):
  function p_iserr_function (line 769) | def p_iserr_function(p):
  function p_if_function (line 774) | def p_if_function(p):
  function p_and_function (line 781) | def p_and_function(p):
  function p_or_function (line 786) | def p_or_function(p):
  function p_fl_reference (line 791) | def p_fl_reference(p):
  function p_fl_dde_call (line 827) | def p_fl_dde_call(p):
  function p_fl_cell_range (line 832) | def p_fl_cell_range(p):
  function GetWorksheetNameFromPotentialNakedWorksheetReference (line 853) | def GetWorksheetNameFromPotentialNakedWorksheetReference(nameOrNWRef):
  function _interpretHorribleFLReferenceMess (line 861) | def _interpretHorribleFLReferenceMess(p, simpleInterpreter):
  function _asCellReference (line 884) | def _asCellReference(cellName, worksheetInfo):
  function p_fl_cell_reference (line 890) | def p_fl_cell_reference(p):
  function _asColumnReference (line 901) | def _asColumnReference(columnName, worksheetInfo):
  function p_fl_column_reference (line 908) | def p_fl_column_reference(p):
  function _asRowReference (line 919) | def _asRowReference(rowName, worksheetInfo):
  function p_fl_row_reference (line 927) | def p_fl_row_reference(p):
  function _asNamedColumnReference (line 938) | def _asNamedColumnReference(columnName, worksheetInfo):
  function p_fl_named_column_reference (line 943) | def p_fl_named_column_reference(p):
  function _asNamedRowReference (line 954) | def _asNamedRowReference(rowName, worksheetInfo):
  function p_fl_named_row_reference (line 959) | def p_fl_named_row_reference(p):
  function p_fl_deleted_reference (line 970) | def p_fl_deleted_reference(p):
  function p_fl_invalid_reference (line 990) | def p_fl_invalid_reference(p):
  function p_fl_naked_worksheet_reference (line 1010) | def p_fl_naked_worksheet_reference(p):
  function p_error (line 1025) | def p_error(p):

FILE: dirigible/sheet/parser/parse_node.py
  class ParseNode (line 6) | class ParseNode(object):
    method __init__ (line 62) | def __init__(self, _type, children):
    method __repr__ (line 67) | def __repr__(self):
    method __eq__ (line 76) | def __eq__(self, other):
    method __ne__ (line 94) | def __ne__(self, other):
    method __hash__ (line 98) | def __hash__(self):
    method flatten (line 102) | def flatten(self):
    method register_node_type (line 113) | def register_node_type(cls, nodeType, nodeClass):
    method construct_node (line 118) | def construct_node(cls, nodeType, children):

FILE: dirigible/sheet/parser/parse_node_constructors.py
  function ConcatExpr (line 14) | def ConcatExpr(children):
  function AndTest (line 17) | def AndTest(children):
  function ArgList (line 20) | def ArgList(children):
  function Argument (line 23) | def Argument(children):
  function ArithExpr (line 26) | def ArithExpr(children):
  function Atom (line 29) | def Atom(children):
  function FLDDECall (line 32) | def FLDDECall(children):
  function FLDeletedReference (line 35) | def FLDeletedReference(children):
  function FLInvalidReference (line 38) | def FLInvalidReference(children):
  function FLNakedWorksheetReference (line 41) | def FLNakedWorksheetReference(children):
  function FLReference (line 44) | def FLReference(children):
  function FLRoot (line 47) | def FLRoot(children):
  function Comparison (line 50) | def Comparison(children):
  function CompOperator (line 53) | def CompOperator(children):
  function DictMaker (line 56) | def DictMaker(children):
  function Expr (line 59) | def Expr(children):
  function ExprList (line 62) | def ExprList(children):
  function Factor (line 65) | def Factor(children):
  function FPDef (line 68) | def FPDef(children):
  function FPList (line 71) | def FPList(children):
  function GenFor (line 74) | def GenFor(children):
  function GenIf (line 77) | def GenIf(children):
  function GenIter (line 80) | def GenIter(children):
  function LambDef (line 83) | def LambDef(children):
  function ListFor (line 86) | def ListFor(children):
  function ListIf (line 89) | def ListIf(children):
  function ListIter (line 92) | def ListIter(children):
  function ListMaker (line 95) | def ListMaker(children):
  function Name (line 98) | def Name(children):
  function NotTest (line 101) | def NotTest(children):
  function Number (line 104) | def Number(children):
  function Percent (line 107) | def Percent(children):
  function Power (line 110) | def Power(children):
  function ShiftExpr (line 113) | def ShiftExpr(children):
  function SliceOp (line 116) | def SliceOp(children):
  function StringLiteral (line 119) | def StringLiteral(children):
  function Subscript (line 122) | def Subscript(children):
  function SubscriptList (line 125) | def SubscriptList(children):
  function Term (line 128) | def Term(children):
  function Test (line 131) | def Test(children):
  function TestList (line 134) | def TestList(children):
  function TestListGexp (line 137) | def TestListGexp(children):
  function Trailer (line 140) | def Trailer(children):
  function VarArgsList (line 143) | def VarArgsList(children):
  function ArithExpr_Term (line 148) | def ArithExpr_Term(mExprChild):
  function Expr_ConcatExpr_ShiftExpr (line 151) | def Expr_ConcatExpr_ShiftExpr(shiftExprChild):
  function Factor_Power_FLReference_Atom (line 154) | def Factor_Power_FLReference_Atom(*atomChildren):
  function Test_AndTest_NotTest_Comparison (line 157) | def Test_AndTest_NotTest_Comparison(comparisonChild):
  function ExprFromAtomChild (line 162) | def ExprFromAtomChild(atomChild):
  function ExprFromAtomChildren (line 166) | def ExprFromAtomChildren(atomChildren):
  function ExprFromNameChild (line 170) | def ExprFromNameChild(nameChild):
  function TestFromAtomChild (line 173) | def TestFromAtomChild(atomChild):
  function TestFromPowerChild (line 177) | def TestFromPowerChild(powerChild):

FILE: dirigible/sheet/parser/parser.py
  function parse (line 25) | def parse(string):

FILE: dirigible/sheet/parser/tokens.py
  function TokenRule (line 151) | def TokenRule(docstring):
  function t_FLNAKEDWORKSHEETREFERENCE (line 160) | def t_FLNAKEDWORKSHEETREFERENCE(t) : return t
  function t_LONGCELLREFERENCE (line 163) | def t_LONGCELLREFERENCE(t): return t
  function t_LONGCOLUMNREFERENCE (line 166) | def t_LONGCOLUMNREFERENCE(t): return t
  function t_LONGNAMEDCOLUMNREFERENCE (line 169) | def t_LONGNAMEDCOLUMNREFERENCE(t): return t
  function t_LONGNAMEDROWREFERENCE (line 172) | def t_LONGNAMEDROWREFERENCE(t): return t
  function t_LONGROWREFERENCE (line 175) | def t_LONGROWREFERENCE(t): return t
  function t_LONGDELETEDREFERENCE (line 178) | def t_LONGDELETEDREFERENCE(t): return t
  function t_LONGINVALIDREFERENCE (line 181) | def t_LONGINVALIDREFERENCE(t): return t
  function t_IMAGINARY (line 184) | def t_IMAGINARY(t): return t
  function t_FLOATNUMBER (line 187) | def t_FLOATNUMBER(t): return t
  function t_HEXINTEGER (line 190) | def t_HEXINTEGER(t): return t
  function t_OCTINTEGER (line 193) | def t_OCTINTEGER(t): return t
  function t_DECINTEGER (line 196) | def t_DECINTEGER(t): return t
  function t_SLONGSTRING (line 199) | def t_SLONGSTRING(t): return t
  function t_DLONGSTRING (line 202) | def t_DLONGSTRING(t): return t
  function t_SSHORTSTRING (line 205) | def t_SSHORTSTRING(t): return t
  function t_DSHORTSTRING (line 208) | def t_DSHORTSTRING(t): return t
  function t_FLNAMEDROWREFERENCE (line 240) | def t_FLNAMEDROWREFERENCE(t):
  function t_TEXT (line 246) | def t_TEXT(t):
  function dollarError (line 265) | def dollarError(t):
  function keywordError (line 269) | def keywordError(t):
  function t_error (line 273) | def t_error(t):

FILE: dirigible/sheet/rewrite_formula_offset_cell_references.py
  function rewrite_source_sheet_formulae_for_cut (line 13) | def rewrite_source_sheet_formulae_for_cut(worksheet, source_range, dest_...
  function rewrite_formula (line 21) | def rewrite_formula(

FILE: dirigible/sheet/sheet.py
  class Sheet (line 19) | class Sheet(models.Model):
    method __init__ (line 55) | def __init__(self, *args, **kwargs):
    method __unicode__ (line 61) | def __unicode__(self):
    method create_private_key (line 65) | def create_private_key(self):
    method _delete_private_key (line 71) | def _delete_private_key(self):
    method save (line 75) | def save(self, *args, **kwargs):
    method unjsonify_worksheet (line 83) | def unjsonify_worksheet(self):
    method jsonify_worksheet (line 87) | def jsonify_worksheet(self, worksheet):
    method merge_non_calc_attrs (line 91) | def merge_non_calc_attrs(self, sheet_in_db):
    method calculate (line 96) | def calculate(self):

FILE: dirigible/sheet/tests/parser/test_fl_cell_range_parse_node.py
  class FLCellRangeParseNodeTest (line 14) | class FLCellRangeParseNodeTest(unittest.TestCase):
    method testConstructor (line 16) | def testConstructor(self):
    method testStr (line 23) | def testStr(self):
    method testRegisteredWithParse (line 30) | def testRegisteredWithParse(self):
    method testCellReferences (line 39) | def testCellReferences(self):
    method testColon (line 55) | def testColon(self):

FILE: dirigible/sheet/tests/parser/test_fl_cell_reference_parse_node.py
  class FLCellReferenceParseNodeTest (line 14) | class FLCellReferenceParseNodeTest(unittest.TestCase):
    method testConstructor (line 16) | def testConstructor(self):
    method testStr (line 23) | def testStr(self):
    method testColAbsolute (line 28) | def testColAbsolute(self):
    method testRowAbsolute (line 39) | def testRowAbsolute(self):
    method testPlainCellName (line 51) | def testPlainCellName(self):
    method testRegisteredWithParse (line 63) | def testRegisteredWithParse(self):
    method testCellProperty (line 69) | def testCellProperty(self):
    method testCanonicalise (line 85) | def testCanonicalise(self):
    method testOffset (line 92) | def testOffset(self):
    method testCoords (line 130) | def testCoords(self):

FILE: dirigible/sheet/tests/parser/test_fl_coloumn_reference_parse_node.py
  class FLColumnReferenceParseNodeTest (line 14) | class FLColumnReferenceParseNodeTest(unittest.TestCase):
    method testConstructor (line 16) | def testConstructor(self):
    method testStr (line 23) | def testStr(self):
    method testIsAbsolute (line 28) | def testIsAbsolute(self):
    method testPlainColumnName (line 39) | def testPlainColumnName(self):
    method testRegisteredWithParse (line 49) | def testRegisteredWithParse(self):
    method testSettingPlainColumnName (line 55) | def testSettingPlainColumnName(self):
    method testColumnReferenceProperty (line 65) | def testColumnReferenceProperty(self):
    method testSettingColumnProperty (line 70) | def testSettingColumnProperty(self):
    method testColIndexProperty (line 80) | def testColIndexProperty(self):
    method testCanonicalise (line 85) | def testCanonicalise(self):
    method testOffset (line 92) | def testOffset(self):
    method testOffsetAbsoluteRefs (line 104) | def testOffsetAbsoluteRefs(self):
    method testCoords (line 113) | def testCoords(self):

FILE: dirigible/sheet/tests/parser/test_fl_named_column_reference_parse_node.py
  class FLNamedColumnReferenceParseNodeTest (line 14) | class FLNamedColumnReferenceParseNodeTest(unittest.TestCase):
    method testConstruct (line 16) | def testConstruct(self):
    method testColumnReference (line 22) | def testColumnReference(self):
    method testRegisteredWithParse (line 29) | def testRegisteredWithParse(self):

FILE: dirigible/sheet/tests/parser/test_fl_named_row_reference_parse_node.py
  class FLNamedRowReferenceParseNodeTest (line 14) | class FLNamedRowReferenceParseNodeTest(unittest.TestCase):
    method testConstruct (line 16) | def testConstruct(self):
    method testRowReference (line 22) | def testRowReference(self):
    method testRegisteredWithParse (line 29) | def testRegisteredWithParse(self):

FILE: dirigible/sheet/tests/parser/test_fl_reference_parse_node.py
  class FLReferenceParseNodeTest (line 14) | class FLReferenceParseNodeTest(unittest.TestCase):
    method testWorksheetReferenceProperty (line 16) | def testWorksheetReferenceProperty(self):
    method testInit (line 38) | def testInit(self):
    method testCanonicalise (line 51) | def testCanonicalise(self):
    method testQuoteFLWorksheetName (line 67) | def testQuoteFLWorksheetName(self):
    method testUnquoteFLWorksheetName (line 77) | def testUnquoteFLWorksheetName(self):

FILE: dirigible/sheet/tests/parser/test_fl_row_reference_parse_node.py
  class FLRowReferenceParseNodeTest (line 15) | class FLRowReferenceParseNodeTest(unittest.TestCase):
    method testConstructor (line 17) | def testConstructor(self):
    method testStr (line 24) | def testStr(self):
    method testIsAbsolute (line 29) | def testIsAbsolute(self):
    method testPlainRowName (line 39) | def testPlainRowName(self):
    method testRegisteredWithParse (line 49) | def testRegisteredWithParse(self):
    method testSettingPlainRowName (line 55) | def testSettingPlainRowName(self):
    method testRowReferenceProperty (line 65) | def testRowReferenceProperty(self):
    method testSettingRowProperty (line 70) | def testSettingRowProperty(self):
    method testRowIndexProperty (line 80) | def testRowIndexProperty(self):
    method testOffset (line 85) | def testOffset(self):
    method testOffsetAbsoluteRefs (line 97) | def testOffsetAbsoluteRefs(self):
    method testCoords (line 106) | def testCoords(self):

FILE: dirigible/sheet/tests/parser/test_parse_node.py
  function Expr (line 13) | def Expr(children):
  function Name (line 16) | def Name(children):
  function ShiftExpr (line 19) | def ShiftExpr(children):
  class ParseNodeTest (line 23) | class ParseNodeTest(unittest.TestCase):
    method testStr (line 25) | def testStr(self):
    method testEquals (line 30) | def testEquals(self):
    method testFlatten (line 46) | def testFlatten(self):
    method testFlattenWithUnicode (line 57) | def testFlattenWithUnicode(self):
    method testFlattenHandlesSubclassed (line 62) | def testFlattenHandlesSubclassed(self):
    method testParseNodeShould (line 73) | def testParseNodeShould(self):

FILE: dirigible/sheet/tests/parser/test_parse_node_constructors.py
  class ParseNodeConstructorsTest (line 76) | class ParseNodeConstructorsTest(unittest.TestCase):
    method testCombinedConvenienceConstructors (line 78) | def testCombinedConvenienceConstructors(self):
    method testSimpleConvenienceConstructors (line 162) | def testSimpleConvenienceConstructors(self):
    method testSubclasses (line 261) | def testSubclasses(self):
    method testFLCell (line 275) | def testFLCell(self):

FILE: dirigible/sheet/tests/parser/test_parser.py
  function ArgListElement (line 74) | def ArgListElement(element):
  function TestFromFlReferenceChildren (line 84) | def TestFromFlReferenceChildren(children):
  function CreateTest (line 92) | def CreateTest(name, lBracket, argList, rBracket):
  function ArgumentFromFLReferenceChild (line 106) | def ArgumentFromFLReferenceChild(child):
  function CreateAndTest (line 111) | def CreateAndTest(operand1, operator, operand2):
  function CreateComparison (line 128) | def CreateComparison(operand1, operator, operand2):
  function CreateParseTree (line 144) | def CreateParseTree(lBracket, test, forStr, exprList, inStr, testListSaf...
  class ParseTreeTest (line 166) | class ParseTreeTest(unittest.TestCase):
    method assertParsesToTree (line 168) | def assertParsesToTree(self, text, expectedTree):
    method assertParsesToFLReferenceChildren (line 172) | def assertParsesToFLReferenceChildren(self, text, children):
    method assertParsesToFLReferenceChild (line 178) | def assertParsesToFLReferenceChild(self, text, child):
    method assertParsesCorrectly (line 182) | def assertParsesCorrectly(self, text, constructExpectedTree):
    method assertCannotParse (line 186) | def assertCannotParse(self, text, errorPosition, errorToken=""):
    method testOne (line 201) | def testOne(self):
    method testFLD (line 211) | def testFLD(self):
    method testFLNaked (line 219) | def testFLNaked(self):
    method testFLNaked2 (line 231) | def testFLNaked2(self):
    method testFLNaked3 (line 238) | def testFLNaked3(self):
    method testWorksheetExpressions (line 259) | def testWorksheetExpressions(self):
    method testFLInvalid (line 278) | def testFLInvalid(self):
    method testFLDeleted (line 296) | def testFLDeleted(self):
    method testFLReference (line 317) | def testFLReference(self):
    method testFLSum (line 342) | def testFLSum(self):
    method testFLCell (line 608) | def testFLCell(self):
    method testCellRangeWith (line 653) | def testCellRangeWith(self):
    method testCellRangeWith2 (line 731) | def testCellRangeWith2(self):
    method testCellRangeWith3 (line 846) | def testCellRangeWith3(self):
    method testCallWithGen (line 883) | def testCallWithGen(self):
    method testPower (line 927) | def testPower(self):
    method testNestedFactor (line 1020) | def testNestedFactor(self):
    method testPercent (line 1036) | def testPercent(self):
    method testFactorFactorTerm (line 1053) | def testFactorFactorTerm(self):
    method testAtomTerm (line 1087) | def testAtomTerm(self):
    method testMultiAtomTerm (line 1113) | def testMultiAtomTerm(self):
    method testAtomArithExpr (line 1135) | def testAtomArithExpr(self):
    method testMultiAtomArith (line 1156) | def testMultiAtomArith(self):
    method testAtomShiftExpr (line 1181) | def testAtomShiftExpr(self):
    method testMultiAtomShift (line 1201) | def testMultiAtomShift(self):
    method testAtomConcatExpr (line 1227) | def testAtomConcatExpr(self):
    method testMultiAtomConcat (line 1246) | def testMultiAtomConcat(self):
    method testExpr (line 1274) | def testExpr(self):
    method testSimpleComparison (line 1296) | def testSimpleComparison(self):
    method testComplexComparison (line 1367) | def testComplexComparison(self):
    method testNotTest (line 1404) | def testNotTest(self):
    method testNotNotTest (line 1422) | def testNotNotTest(self):
    method testAndTest (line 1444) | def testAndTest(self):
    method testMultiAndTest (line 1454) | def testMultiAndTest(self):
    method testTest (line 1487) | def testTest(self):
    method testMultiTest (line 1511) | def testMultiTest(self):
    method testTrivialLambDef (line 1545) | def testTrivialLambDef(self):
    method testSimpleLambDef (line 1563) | def testSimpleLambDef(self):
    method testTrivialStringConversion (line 1809) | def testTrivialStringConversion(self):
    method testComplexStringConversion (line 1835) | def testComplexStringConversion(self):
    method testEmptyParentheses (line 1901) | def testEmptyParentheses(self):
    method testParenthesesWithSingle (line 1922) | def testParenthesesWithSingle(self):
    method testComplexParentheses (line 1944) | def testComplexParentheses(self):
    method testSimpleGeneratorExpr (line 2014) | def testSimpleGeneratorExpr(self):
    method testComplexGeneratorExpr (line 2096) | def testComplexGeneratorExpr(self):
    method testEmptyList (line 2194) | def testEmptyList(self):
    method testListWithNumbers (line 2216) | def testListWithNumbers(self):
    method testListWithSimple (line 2256) | def testListWithSimple(self):
    method testListWithParenthetical (line 2316) | def testListWithParenthetical(self):
    method testListWithList (line 2653) | def testListWithList(self):
    method testEmptyDict (line 2837) | def testEmptyDict(self):
    method testSimpleDict (line 2858) | def testSimpleDict(self):
    method testComplexDictDisplay (line 2886) | def testComplexDictDisplay(self):
    method testOtherErrors (line 2970) | def testOtherErrors(self):
    method testIfFunctionCalls (line 2976) | def testIfFunctionCalls(self):
    method testAndOrFunctions (line 3123) | def testAndOrFunctions(self):
    method testISE (line 3128) | def testISE(self):
    method checkFunction (line 3162) | def checkFunction(self, functionName):
    method testCannotUseInappropriate (line 3223) | def testCannotUseInappropriate(self):
    method testCellRefLike (line 3262) | def testCellRefLike(self):
    method testMissingParametersIn (line 3295) | def testMissingParametersIn(self):
    method testMissingParametersIn2 (line 3315) | def testMissingParametersIn2(self):
  class ParserModuleTest (line 3352) | class ParserModuleTest(unittest.TestCase):
    method test_reloading_module_should_not_regenerate_parsetab (line 3354) | def test_reloading_module_should_not_regenerate_parsetab(self):
    method test_multithreaded_parsing_works (line 3368) | def test_multithreaded_parsing_works(self):

FILE: dirigible/sheet/tests/test_calculate.py
  class TestIsNan (line 34) | class TestIsNan(ResolverTestCase):
    method test_is_nan (line 36) | def test_is_nan(self):
    method test_is_nan_with_numpy (line 41) | def test_is_nan_with_numpy(self):
  class TestLoadConstants (line 51) | class TestLoadConstants(ResolverTestCase):
    method test_load_constants_should_call_eval_constant_only_on_every_constant_location (line 54) | def test_load_constants_should_call_eval_constant_only_on_every_consta...
    method test_load_constants_should_clear_errors_for_constants (line 69) | def test_load_constants_should_clear_errors_for_constants(self):
  class TestRecalculateCell (line 82) | class TestRecalculateCell(ResolverTestCase):
    method test_recalculate_cell_evals_python_formula_in_context_and_puts_results_in_worksheet (line 84) | def test_recalculate_cell_evals_python_formula_in_context_and_puts_res...
    method test_recalculate_cell_should_perform_true_division (line 99) | def test_recalculate_cell_should_perform_true_division(self):
    method test_recalculate_cell_should_remove_nodes_from_dependency_graph (line 114) | def test_recalculate_cell_should_remove_nodes_from_dependency_graph(se...
    method test_recalc_cell_catches_cell_errors_and_adds_them_to_console (line 131) | def test_recalc_cell_catches_cell_errors_and_adds_them_to_console(self):
    method test_recalc_cell_should_clear_cell_error_and_not_add_to_console_text_on_eval_succeeding (line 163) | def test_recalc_cell_should_clear_cell_error_and_not_add_to_console_te...
  class TestCreateCellRecalculator (line 192) | class TestCreateCellRecalculator(ResolverTestCase):
    method test_create_cell_recalculator_should (line 195) | def test_create_cell_recalculator_should(self, mock_recalculate):
    method test_create_cell_recalculator_should_handle_exceptions_from_recalc_cell (line 231) | def test_create_cell_recalculator_should_handle_exceptions_from_recalc...
  class TestEvaluateFormulaeInContext (line 251) | class TestEvaluateFormulaeInContext(ResolverTestCase):
    method test_evaluate_formulae_in_context_builds_dependency_graph_and_recalculates_it_on_threads (line 258) | def test_evaluate_formulae_in_context_builds_dependency_graph_and_reca...
  class TestExecuteUsercode (line 320) | class TestExecuteUsercode(ResolverTestCase):
    method test_execute_usercode_does (line 322) | def test_execute_usercode_does(self):
  class TestCalculate (line 334) | class TestCalculate(ResolverTestCase):
    method test_calculate_should_execute_usercode_with_correct_context_and_curried_evaluate_formulae_in_context (line 338) | def test_calculate_should_execute_usercode_with_correct_context_and_cu...
    method test_calculate_patches_sys_stdout_in_context (line 368) | def test_calculate_patches_sys_stdout_in_context(
    method test_mystdout_pushes_print_commands_to_worksheet (line 383) | def test_mystdout_pushes_print_commands_to_worksheet(self):
    method test_calculate_puts_curried_run_worksheet_into_context (line 394) | def test_calculate_puts_curried_run_worksheet_into_context(self, mock_...
    method test_calculate_clears_previous_worksheet_cell_values_before_executing_usercode (line 410) | def test_calculate_clears_previous_worksheet_cell_values_before_execut...
    method test_calculate_clears_previous_worksheet_console_text_and_reports_time (line 428) | def test_calculate_clears_previous_worksheet_console_text_and_reports_...
    method test_calculate_clears_previous_worksheet_console_text_and_reports_time_when_theres_an_error (line 447) | def test_calculate_clears_previous_worksheet_console_text_and_reports_...
    method test_calculate_clears_previous_worksheet_usercode_error (line 469) | def test_calculate_clears_previous_worksheet_usercode_error(self, mock...
    method test_calculate_catches_usercode_exceptions (line 479) | def test_calculate_catches_usercode_exceptions(self, mock_execute_user...
    method test_calculate_catches_and_reports_exceptions_in_worksheet_usercode_error_field (line 492) | def test_calculate_catches_and_reports_exceptions_in_worksheet_usercod...
    method test_calculate_catches_and_reports_syntax_errors_with_special_message_in_worksheet_usercode_error_field (line 510) | def test_calculate_catches_and_reports_syntax_errors_with_special_mess...
    method test_calculate_catches_and_reports_exceptions_to_console (line 530) | def test_calculate_catches_and_reports_exceptions_to_console(self):
    method test_calculate_catches_and_reports_syntax_errors_to_console (line 561) | def test_calculate_catches_and_reports_syntax_errors_to_console(self, ...
    method test_format_traceback_filters_frames_that_are_dirigible_code (line 577) | def test_format_traceback_filters_frames_that_are_dirigible_code(self):
  class TestCalculateWithTimeout (line 607) | class TestCalculateWithTimeout(ResolverTestCase):
    method test_calculate_with_timeout_calls_calculate_function_with_contents_and_usercode (line 610) | def test_calculate_with_timeout_calls_calculate_function_with_contents...
    method test_calculate_with_timeout_uses_interruptable_thread_with_correct_timeout (line 626) | def test_calculate_with_timeout_uses_interruptable_thread_with_correct...
    method test_calculate_with_timeout_tries_to_interrupt_timed_out_thread (line 646) | def test_calculate_with_timeout_tries_to_interrupt_timed_out_thread(
  class TestRaise (line 676) | class TestRaise(ResolverTestCase):
    method test_raise_raises (line 678) | def test_raise_raises(self):
  class TestRunWorksheet (line 686) | class TestRunWorksheet(ResolverTestCase):
    method test_run_worksheet_no_overrides (line 690) | def test_run_worksheet_no_overrides(self, mock_api_json_to_worksheet, ...
    method test_run_worksheet_with_overrides (line 709) | def test_run_worksheet_with_overrides(self, mock_api_json_to_worksheet...
    method test_run_worksheet_with_error (line 731) | def test_run_worksheet_with_error(self, mock_urllib2):
    method test_run_worksheet_passes_private_key_in_params (line 743) | def test_run_worksheet_passes_private_key_in_params(self, mock_api_jso...
  class TestJsonToWorksheet (line 759) | class TestJsonToWorksheet(ResolverTestCase):
    method test_values (line 761) | def test_values(self):
    method test_should_call_worksheets_without_name_untitled (line 787) | def test_should_call_worksheets_without_name_untitled(self):
    method test_should_copy_errors_across (line 796) | def test_should_copy_errors_across(self):
  class TestCalculateSemiFunctional (line 814) | class TestCalculateSemiFunctional(ResolverTestCase):
    method test_totally_empty (line 816) | def test_totally_empty(self):
    method test_empty_worksheet (line 822) | def test_empty_worksheet(self):
    method test_constant (line 828) | def test_constant(self):
    method test_multiple_constants (line 837) | def test_multiple_constants(self):
    method test_arithmetic (line 853) | def test_arithmetic(self):
    method test_formulae (line 870) | def test_formulae(self):
    method test_python_formulae (line 890) | def test_python_formulae(self):
    method test_preformula_usercode (line 904) | def test_preformula_usercode(self):
    method test_postformula_usercode (line 921) | def test_postformula_usercode(self):
    method test_preformula_usercode_functions (line 935) | def test_preformula_usercode_functions(self):
    method test_run_worksheet_should_return_worksheet_with_calculated_values_only (line 955) | def test_run_worksheet_should_return_worksheet_with_calculated_values_...
    method test_run_worksheet_with_overrides (line 995) | def test_run_worksheet_with_overrides(self, mock_urllib2):

FILE: dirigible/sheet/tests/test_cell.py
  class TestUndefined (line 18) | class TestUndefined(unittest.TestCase):
    method test_repr (line 20) | def test_repr(self):
  class TestCell (line 25) | class TestCell(ResolverTestCase):
    method test_initialisation (line 27) | def test_initialisation(self):
    method test_clear_value_clears_value_but_not_formatted_value (line 36) | def test_clear_value_clears_value_but_not_formatted_value(self):
    method test_clear_clears_stuff (line 48) | def test_clear_clears_stuff(self):
    method test_setting_value_to_ws_doesnt_die (line 68) | def test_setting_value_to_ws_doesnt_die(self):
    method test_setting_value_to_undefined_sets_formatted_value_to_empty_string (line 76) | def test_setting_value_to_undefined_sets_formatted_value_to_empty_stri...
    method test_setting_value_sets_formatted_value_to_unicode_version (line 82) | def test_setting_value_sets_formatted_value_to_unicode_version(self):
    method test_setting_formatted_value_to_string_passes_through (line 89) | def test_setting_formatted_value_to_string_passes_through(self):
    method test_setting_formatted_value_to_non_string_explodes (line 95) | def test_setting_formatted_value_to_non_string_explodes(self):
    method test_setting_formatted_value_to_none (line 105) | def test_setting_formatted_value_to_none(self):
    method test_setting_formatted_value_to_unicode (line 111) | def test_setting_formatted_value_to_unicode(self):
    method test_setting_formula_to_string_passes_through (line 117) | def test_setting_formula_to_string_passes_through(self):
    method test_setting_formula_to_non_string_explodes (line 123) | def test_setting_formula_to_non_string_explodes(self):
    method test_setting_formula_to_none_works_and_sets_python_formula_to_none (line 133) | def test_setting_formula_to_none_works_and_sets_python_formula_to_none...
    method test_setting_formula_to_constant_clears_python_formula (line 143) | def test_setting_formula_to_constant_clears_python_formula(self):
    method test_setting_formula_parses_formula_sets_dependencies_then_sets_python_formula (line 155) | def test_setting_formula_parses_formula_sets_dependencies_then_sets_py...
    method test_setting_formula_with_syntax_error_sets_appropriate_raise_in_python_formula_and_clears_dependencies (line 193) | def test_setting_formula_with_syntax_error_sets_appropriate_raise_in_p...
    method test_setting_python_formula_to_non_string_explodes (line 224) | def test_setting_python_formula_to_non_string_explodes(self):
    method test_can_use_unicode_in_formula (line 236) | def test_can_use_unicode_in_formula(self):
    method test_repr (line 242) | def test_repr(self):
    method test_eq_neq (line 274) | def test_eq_neq(self):

FILE: dirigible/sheet/tests/test_cell_range.py
  class TestCellRanges (line 21) | class TestCellRanges(ResolverTestCase):
    method setUp (line 22) | def setUp(self):
    method test_constructor_with_only_worksheet_fails (line 31) | def test_constructor_with_only_worksheet_fails(self):
    method test_constructor_with_start_and_end (line 34) | def test_constructor_with_start_and_end(self):
    method test_constructor_inverted (line 42) | def test_constructor_inverted(self):
    method test_equality (line 55) | def test_equality(self):
    method test_repr (line 77) | def test_repr(self):
    method test_edges (line 82) | def test_edges(self):
    method test_len (line 89) | def test_len(self):
    method test_iterators_with_start_and_end (line 94) | def test_iterators_with_start_and_end(self):
    method test_iterators_with_start_and_end_inverted (line 102) | def test_iterators_with_start_and_end_inverted(self):
    method test_indexing_by_tuple (line 109) | def test_indexing_by_tuple(self):
    method test_indexing_edge_cases (line 124) | def test_indexing_edge_cases(self):
    method test_indexing_backwards (line 148) | def test_indexing_backwards(self):
    method test_setitem_on_nonexistent_cell (line 160) | def test_setitem_on_nonexistent_cell(self):
    method test_iterator_with_locations (line 170) | def test_iterator_with_locations(self):
    method test_clear_should_call_clear_on_member_cells (line 181) | def test_clear_should_call_clear_on_member_cells(self):

FILE: dirigible/sheet/tests/test_clipboard.py
  class ClipboardModelTest (line 19) | class ClipboardModelTest(ResolverTestCase):
    method test_initial_fields (line 21) | def test_initial_fields(self):
    method test_source_range (line 35) | def test_source_range(self):
    method test_width_and_height (line 45) | def test_width_and_height(self):
    method test_clipboad_copy_retrieves_stuff_from_sheet_and_removes_offset (line 57) | def test_clipboad_copy_retrieves_stuff_from_sheet_and_removes_offset(s...
    method test_cut_calls_copy_then_cuts_and_remembers_some_stuff (line 94) | def test_cut_calls_copy_then_cuts_and_remembers_some_stuff(self):
    method test_clipboard_remembers_to_close_stingIO_stream (line 128) | def test_clipboard_remembers_to_close_stingIO_stream(self, mock_string...
    method test_clipboard_json_to_cells (line 136) | def test_clipboard_json_to_cells(self):
    method test_paste_to_for_copy (line 173) | def test_paste_to_for_copy(self):
    method test_paste_to_for_cut_different_sheet (line 213) | def test_paste_to_for_cut_different_sheet(self):
    method test_copy_then_paste_same_sheet (line 275) | def test_copy_then_paste_same_sheet(self):
    method test_cut_then_paste_same_sheet (line 300) | def test_cut_then_paste_same_sheet(self):
    method test_paste_to_should_tile_clipboard_contents_across_selected_range (line 333) | def test_paste_to_should_tile_clipboard_contents_across_selected_range...
  class FormulaRewriteTest (line 378) | class FormulaRewriteTest(ResolverTestCase):
    method test_formulae_are_rewritten (line 381) | def test_formulae_are_rewritten(self, mock_rewrite):
    method test_paste_from_cut_rewrites_source_worksheet_formulae_before_pasting (line 400) | def test_paste_from_cut_rewrites_source_worksheet_formulae_before_past...
    method test_paste_from_copy_does_not_rewrite_source_sheet_formulae (line 426) | def test_paste_from_copy_does_not_rewrite_source_sheet_formulae(
    method test_paste_onto_different_sheet_from_cut_does_not_rewrite_source_sheet_formulae (line 449) | def test_paste_onto_different_sheet_from_cut_does_not_rewrite_source_s...

FILE: dirigible/sheet/tests/test_dependency_graph.py
  class TestBuildDependencyGraph (line 20) | class TestBuildDependencyGraph(ResolverTestCase):
    method test_returns_graph_and_leaf_nodes (line 22) | def test_returns_graph_and_leaf_nodes(self):
    method test_is_robust_against_references_to_empty_cells (line 99) | def test_is_robust_against_references_to_empty_cells(self):
    method test_puts_errors_on_cells_in_cycles_and_omits_them_from_graph (line 123) | def test_puts_errors_on_cells_in_cycles_and_omits_them_from_graph(self...
  class TestGenerateCellSubgraph (line 152) | class TestGenerateCellSubgraph(ResolverTestCase):
    method test_should_recursively_call_itself_on_dependencies_before_adding_dependencies_to_graph (line 156) | def test_should_recursively_call_itself_on_dependencies_before_adding_...
    method test_should_add_dependencies_to_graph (line 192) | def test_should_add_dependencies_to_graph(
    method test_should_remove_dependencies_with_errors_and_empty_cells (line 210) | def test_should_remove_dependencies_with_errors_and_empty_cells(
    method test_should_report_cell_error_and_not_add_location_on_recursive_call_raising_cycle_error_if_location_is_not_in_cycle_path (line 230) | def test_should_report_cell_error_and_not_add_location_on_recursive_ca...
    method test_should_add_cell_to_graph_if_formula_not_set_but_python_formula_is (line 244) | def test_should_add_cell_to_graph_if_formula_not_set_but_python_formul...
    method test_should_not_reprocess_locations_already_in_visited_even_if_it_is_in_worksheet (line 256) | def test_should_not_reprocess_locations_already_in_visited_even_if_it_...
    method test_should_add_location_to_visited_set_after_recursing_deps (line 271) | def test_should_add_location_to_visited_set_after_recursing_deps(
    method test_should_safely_handle_nonexistent_location (line 290) | def test_should_safely_handle_nonexistent_location(self):
    method test_should_report_then_raise_cycle_error_when_there_is_a_cycle (line 296) | def test_should_report_then_raise_cycle_error_when_there_is_a_cycle(
    method test_should_raise_any_existing_cycle_error_for_visited_locations (line 315) | def test_should_raise_any_existing_cycle_error_for_visited_locations(s...
    method test_should_reraise_cycle_error_after_reporting_if_its_in_the_cycle_path (line 331) | def test_should_reraise_cycle_error_after_reporting_if_its_in_the_cycl...
    method test_should_not_reraise_cycle_error_if_its_outside_the_cycle_path (line 354) | def test_should_not_reraise_cycle_error_if_its_outside_the_cycle_path(
    method test_should_not_recurse_into_existing_cycle_errors_or_include_them_in_its_deps (line 366) | def test_should_not_recurse_into_existing_cycle_errors_or_include_them...
    method test_does_not_include_discovered_cycle_in_deps_of_current_cell (line 386) | def test_does_not_include_discovered_cycle_in_deps_of_current_cell(sel...
    method test_reports_error_once_per_cell (line 401) | def test_reports_error_once_per_cell(self, mock_report_cell_error):
  class TestDependencyGraphNode (line 415) | class TestDependencyGraphNode(ResolverTestCase):
    method test_constructor (line 417) | def test_constructor(self):
    method test_nodes_should_have_a_lock (line 435) | def test_nodes_should_have_a_lock(self):
    method test_equality (line 440) | def test_equality(self):
    method test_repr (line 466) | def test_repr(self):
    method test_remove_should_acquire_lock_on_parent_nodes (line 472) | def test_remove_should_acquire_lock_on_parent_nodes(self):
    method test_remove_should_add_new_leaves_to_queue (line 501) | def test_remove_should_add_new_leaves_to_queue(self):
  class TestAddLocationDependencies (line 517) | class TestAddLocationDependencies(ResolverTestCase):
    method test_add_location_dependencies_does (line 519) | def test_add_location_dependencies_does(self):
    method test_add_location_dependencies_also_adds_reverse_dependencies (line 526) | def test_add_location_dependencies_also_adds_reverse_dependencies(self):

FILE: dirigible/sheet/tests/test_dirigible_datetime.py
  class DateTimeTest (line 14) | class DateTimeTest(ResolverTestCase):
    method test_DateTime_subclasses_datetime_dot_datetime (line 16) | def test_DateTime_subclasses_datetime_dot_datetime(self):

FILE: dirigible/sheet/tests/test_errors.py
  class TestCycleError (line 18) | class TestCycleError(unittest.TestCase):
    method test_cycle_error_str_reports_path (line 20) | def test_cycle_error_str_reports_path(self):
    method test_cycle_error_repr_reports_path (line 25) | def test_cycle_error_repr_reports_path(self):
    method test_cycle_errors_compare_unequal_to_random_crap (line 30) | def test_cycle_errors_compare_unequal_to_random_crap(self):
    method test_cycle_errors_compare_equal_from_identical_path (line 36) | def test_cycle_errors_compare_equal_from_identical_path(self):
    method test_cycle_errors_compare_unequal_from_different_paths (line 43) | def test_cycle_errors_compare_unequal_from_different_paths(self):
  class TestReportCellError (line 50) | class TestReportCellError(unittest.TestCase):
    method test_report_cell_error (line 52) | def test_report_cell_error(self):

FILE: dirigible/sheet/tests/test_eval_constant.py
  class TestEvalConstant (line 13) | class TestEvalConstant(unittest.TestCase):
    method test_returns_input_unchanged_in_general (line 15) | def test_returns_input_unchanged_in_general(self):
    method test_returns_float_for_floatlike_input (line 20) | def test_returns_float_for_floatlike_input(self):

FILE: dirigible/sheet/tests/test_forms.py
  class TestImportCSVForm (line 9) | class TestImportCSVForm(ResolverTestCase):
    method test_initialisation (line 11) | def test_initialisation(self):
    method test_hidden_fields_appear_with_correct_ids (line 19) | def test_hidden_fields_appear_with_correct_ids(self):

FILE: dirigible/sheet/tests/test_formula_interpreter.py
  class TestGetPythonFormulaFromParseTree (line 25) | class TestGetPythonFormulaFromParseTree(ResolverTestCase):
    method test_flattens_rewrites_and_removes_1st_char (line 28) | def test_flattens_rewrites_and_removes_1st_char(self, mock_rewrite):
    method test_converts_formula_starting_with_equals (line 39) | def test_converts_formula_starting_with_equals(self):
    method test_converts_cell_references_and_adds_space (line 44) | def test_converts_cell_references_and_adds_space(self):
    method test_produces_correct_python (line 51) | def test_produces_correct_python(self):
  class TestRewrite (line 75) | class TestRewrite(ResolverTestCase):
    method test_slicing_in_formulae (line 77) | def test_slicing_in_formulae(self):
    method test_rewrite_string_should_return_object_unchanged (line 100) | def test_rewrite_string_should_return_object_unchanged(self):
    method test_rewrite_parse_node_should_return_parse_node_with_children_rewritten (line 106) | def test_rewrite_parse_node_should_return_parse_node_with_children_rew...
    method test_rewrite_cell_reference_should_return_appropriate_tree (line 132) | def test_rewrite_cell_reference_should_return_appropriate_tree(self):
    method test_rewrite_should_translate_lambda_arrow_to_colon (line 139) | def test_rewrite_should_translate_lambda_arrow_to_colon(self):
    method test_rewrite_should_translate_dictionary_arrow_to_colon (line 161) | def test_rewrite_should_translate_dictionary_arrow_to_colon(self):
    method test_rewrite_should_raise_invalid_cell_reference_error_when_appropriate (line 178) | def test_rewrite_should_raise_invalid_cell_reference_error_when_approp...
    method test_rewrite_should_raise_deleted_cell_reference_error_when_appropriate (line 188) | def test_rewrite_should_raise_deleted_cell_reference_error_when_approp...
  class TestGetParseTreeDependencies (line 199) | class TestGetParseTreeDependencies(ResolverTestCase):
    method test_get_parse_tree_dependencies_should_return_empty_list_when_no_cell_refs (line 201) | def test_get_parse_tree_dependencies_should_return_empty_list_when_no_...
    method test_get_parse_tree_dependencies_should_return_locations_for_simple_expression (line 206) | def test_get_parse_tree_dependencies_should_return_locations_for_simpl...
    method test_get_parse_tree_dependencies_should_return_locations_for_simple_expression_with_case_mismatch (line 211) | def test_get_parse_tree_dependencies_should_return_locations_for_simpl...
    method test_get_parse_tree_dependencies_should_return_locations_disregarding_worksheet_names (line 216) | def test_get_parse_tree_dependencies_should_return_locations_disregard...
    method test_get_parse_tree_dependencies_should_return_locations_used_for_function_calls_and_arguments (line 221) | def test_get_parse_tree_dependencies_should_return_locations_used_for_...
    method test_get_parse_tree_dependencies_should_not_return_locations_for_invalid_references (line 226) | def test_get_parse_tree_dependencies_should_not_return_locations_for_i...
    method test_get_parse_tree_dependencies_should_not_return_locations_for_deleted_references (line 231) | def test_get_parse_tree_dependencies_should_not_return_locations_for_d...
    method test_get_parse_tree_dependencies_should_not_return_locations_for_invalid_references_in_cell_ranges (line 236) | def test_get_parse_tree_dependencies_should_not_return_locations_for_i...
    method test_get_parse_tree_dependencies_should_not_return_locations_for_deleted_references_in_cell_ranges (line 242) | def test_get_parse_tree_dependencies_should_not_return_locations_for_d...
    method test_get_parse_tree_dependencies_should_not_return_locations_for_worksheet_references (line 248) | def test_get_parse_tree_dependencies_should_not_return_locations_for_w...
    method test_get_parse_tree_dependencies_should_return_cellrange_deps (line 254) | def test_get_parse_tree_dependencies_should_return_cellrange_deps(self):

FILE: dirigible/sheet/tests/test_importer.py
  class WorksheetFromCSVTest (line 24) | class WorksheetFromCSVTest(ResolverTestCase):
    method test_should_put_data_into_existing_worksheet_with_offset_for_excel_and_auto (line 26) | def test_should_put_data_into_existing_worksheet_with_offset_for_excel...
    method test_excel_csv_import_recognises_accents_and_currency_symbols (line 53) | def test_excel_csv_import_recognises_accents_and_currency_symbols(self):
    method test_excel_csv_import_handles_carriage_returns_in_cells (line 68) | def test_excel_csv_import_handles_carriage_returns_in_cells(self):
    method test_autodetect_csv_import_handles_carriage_returns_in_cells (line 82) | def test_autodetect_csv_import_handles_carriage_returns_in_cells(self):
    method test_autodetect_can_handle_japanese_utf8 (line 96) | def test_autodetect_can_handle_japanese_utf8(self):
    method test_excel_csv_import_survives_japanes_utf8 (line 109) | def test_excel_csv_import_survives_japanes_utf8(self):
    method test_import_excel_csv_raises_on_null_bytes (line 121) | def test_import_excel_csv_raises_on_null_bytes(self):
    method test_autodetect_import_csv_raises_on_null_bytes (line 132) | def test_autodetect_import_csv_raises_on_null_bytes(self):
    method test_autodetect_import_csv_raises_on_failure_to_detect_encoding (line 145) | def test_autodetect_import_csv_raises_on_failure_to_detect_encoding(
  class WorksheetFromExcelTest (line 163) | class WorksheetFromExcelTest(ResolverTestCase):
    method test_populates_worksheet_formulae_from_excel_values (line 165) | def test_populates_worksheet_formulae_from_excel_values(self):
    method test_populates_worksheet_handles_float_source_values (line 182) | def test_populates_worksheet_handles_float_source_values(self):
    method test_converts_excel_dates_to_python_datetime (line 200) | def test_converts_excel_dates_to_python_datetime(self, mock_xlrd_date_...
    method test_handles_excel_errors (line 228) | def test_handles_excel_errors(self, mock_xlrd_date_as_tuple):

FILE: dirigible/sheet/tests/test_rewrite_formula_offset_cell_references.py
  class TestRewriteFormulaOffsetCellReferences (line 15) | class TestRewriteFormulaOffsetCellReferences(unittest.TestCase):
    method test_dont_rewrite_constants (line 17) | def test_dont_rewrite_constants(self):
    method test_safely_handle_none (line 24) | def test_safely_handle_none(self):
    method test_safely_handle_nonsense (line 28) | def test_safely_handle_nonsense(self):
    method test_cut_cell_reference_to_cut_cell_is_rewritten (line 36) | def test_cut_cell_reference_to_cut_cell_is_rewritten(self):
    method test_cut_cell_reference_to_uncut_cell_is_not_rewritten (line 43) | def test_cut_cell_reference_to_uncut_cell_is_not_rewritten(self):
    method test_absolute_cut_cell_reference_to_uncut_cell_is_not_rewritten (line 50) | def test_absolute_cut_cell_reference_to_uncut_cell_is_not_rewritten(se...
    method test_absolute_cut_cell_reference_to_cut_cell_is_rewritten (line 57) | def test_absolute_cut_cell_reference_to_cut_cell_is_rewritten(self):
    method test_copied_cell_reference_to_copied_cell_is_rewritten (line 64) | def test_copied_cell_reference_to_copied_cell_is_rewritten(self):
    method test_copied_cell_reference_to_uncopied_cell_is_rewritten (line 71) | def test_copied_cell_reference_to_uncopied_cell_is_rewritten(self):
    method test_absolute_copied_cell_reference_to_copied_cell_is_not_rewritten (line 78) | def test_absolute_copied_cell_reference_to_copied_cell_is_not_rewritte...
    method test_absolute_copied_cell_reference_to_uncopied_cell_is_not_rewritten (line 85) | def test_absolute_copied_cell_reference_to_uncopied_cell_is_not_rewrit...
    method test_copied_cell_reference_that_moves_off_grid_marked_invalid (line 92) | def test_copied_cell_reference_that_moves_off_grid_marked_invalid(self):
    method test_cut_cellrange_reference_to_completely_cut_cellrange_is_rewritten (line 99) | def test_cut_cellrange_reference_to_completely_cut_cellrange_is_rewrit...
    method test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rewritten (line 106) | def test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rew...
    method test_cut_absolute_cellrange_reference_to_completely_cut_cellrange_is_rewritten (line 113) | def test_cut_absolute_cellrange_reference_to_completely_cut_cellrange_...
    method test_cut_absolute_cellrange_reference_to_partially_cut_cellrange_is_not_rewritten (line 120) | def test_cut_absolute_cellrange_reference_to_partially_cut_cellrange_i...
    method test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rewritten_even_if_its_not_obviously_overlapping (line 127) | def test_cut_cellrange_reference_to_partially_cut_cellrange_is_not_rew...
    method test_cut_absolute_cellrange_reference_to_partially_cut_cellrange_is_not_rewritten_even_if_its_not_obviously_overlapping (line 145) | def test_cut_absolute_cellrange_reference_to_partially_cut_cellrange_i...
    method test_cut_cellrange_reference_to_uncut_cellrange_is_not_rewritten (line 163) | def test_cut_cellrange_reference_to_uncut_cellrange_is_not_rewritten(s...
    method test_cut_absolute_cellrange_reference_to_uncut_cellrange_is_not_rewritten (line 170) | def test_cut_absolute_cellrange_reference_to_uncut_cellrange_is_not_re...
    method test_copied_cellrange_reference_to_completely_copied_cellrange_is_rewritten (line 177) | def test_copied_cellrange_reference_to_completely_copied_cellrange_is_...
    method test_copied_absolute_cellrange_reference_to_completely_copied_cellrange_is_not_rewritten (line 184) | def test_copied_absolute_cellrange_reference_to_completely_copied_cell...
    method test_copied_cellrange_reference_to_partially_copied_cellrange_is_rewritten (line 191) | def test_copied_cellrange_reference_to_partially_copied_cellrange_is_r...
    method test_copied_absolute_cellrange_reference_to_partially_copied_cellrange_is_not_rewritten (line 198) | def test_copied_absolute_cellrange_reference_to_partially_copied_cellr...
    method test_copied_cellrange_reference_to_uncopied_cellrange_is_rewritten (line 205) | def test_copied_cellrange_reference_to_uncopied_cellrange_is_rewritten...
    method test_copied_absolute_cellrange_reference_to_uncopied_cellrange_is_not_rewritten (line 212) | def test_copied_absolute_cellrange_reference_to_uncopied_cellrange_is_...
    method test_copied_cellrange_reference_that_moves_off_grid_marked_invalid (line 219) | def test_copied_cellrange_reference_that_moves_off_grid_marked_invalid...
    method test_source_sheet_cell_references_to_cut_range_are_rewritten (line 226) | def test_source_sheet_cell_references_to_cut_range_are_rewritten(self):
    method test_source_sheet_cell_ranges_inside_cut_range_are_rewritten (line 243) | def test_source_sheet_cell_ranges_inside_cut_range_are_rewritten(self):

FILE: dirigible/sheet/tests/test_sheet.py
  class CopySheetForUserTest (line 19) | class CopySheetForUserTest(ResolverDjangoTestCase):
    method test_copy_sheet_allows_other_users_to_copy_public_sheets (line 21) | def test_copy_sheet_allows_other_users_to_copy_public_sheets(self):
  class SheetModelTest (line 47) | class SheetModelTest(ResolverDjangoTestCase):
    method test_creation (line 49) | def test_creation(self):
    method test_unicode (line 79) | def test_unicode(self):
    method test_uuid_stays_constant_between_reads (line 87) | def test_uuid_stays_constant_between_reads(self):
    method test_create_private_key_uses_onetimepad (line 97) | def test_create_private_key_uses_onetimepad(self):
    method test_delete_private_key_does (line 111) | def test_delete_private_key_does(self):
    method test_unjsonify_worksheet_should_return_worksheet (line 124) | def test_unjsonify_worksheet_should_return_worksheet(self, mock_worksh...
    method test_jsonify_worksheet_should_write_json_to_contents_json_field (line 135) | def test_jsonify_worksheet_should_write_json_to_contents_json_field(se...
    method test_roundtrip_column_widths_to_db (line 145) | def test_roundtrip_column_widths_to_db(self, mock_json):
    method test_sheet_name_set_on_save_if_name_is_default (line 170) | def test_sheet_name_set_on_save_if_name_is_default(self):
    method test_sheet_name_not_set_on_save_if_name_is_not_default (line 178) | def test_sheet_name_not_set_on_save_if_name_is_not_default(self):
    method test_last_modified (line 187) | def test_last_modified(self):
    method test_version_default (line 192) | def test_version_default(self):
    method test_merge_non_calc_attrs_should_copy_some_attrs (line 197) | def test_merge_non_calc_attrs_should_copy_some_attrs(self):
    method test_calculate_calls_calculate_with_unjsonified_worksheet_and_saves_recalced_json (line 215) | def test_calculate_calls_calculate_with_unjsonified_worksheet_and_save...
    method test_calculate_always_deletes_private_key_in_finally_block (line 239) | def test_calculate_always_deletes_private_key_in_finally_block(

FILE: dirigible/sheet/tests/test_ui_jsonifier.py
  class TestSheetToUIJsonGridData (line 25) | class TestSheetToUIJsonGridData(unittest.TestCase):
    method test_to_ui_json_grid_zero_size (line 27) | def test_to_ui_json_grid_zero_size(self):
    method test_to_ui_json_grid_ten_by_five_with_content_and_large_range (line 37) | def test_to_ui_json_grid_ten_by_five_with_content_and_large_range(self):
    method test_to_ui_json_grid_ten_by_five_with_content_and_small_range (line 83) | def test_to_ui_json_grid_ten_by_five_with_content_and_small_range(self):
    method test_to_ui_json_grid (line 126) | def test_to_ui_json_grid(self):
    method test_sheet_to_ui_json_grid_data_should_not_contain_undefined_cell_values_or_empty_formatted_values (line 152) | def test_sheet_to_ui_json_grid_data_should_not_contain_undefined_cell_...
    method test_sheet_to_ui_json_grid_data_should_not_contain_none_cell_formulae (line 168) | def test_sheet_to_ui_json_grid_data_should_not_contain_none_cell_formu...
    method test_sheet_to_ui_json_grid_data_should_not_include_totally_empty_cells (line 184) | def test_sheet_to_ui_json_grid_data_should_not_include_totally_empty_c...
    method test_to_ui_json_grid_includes_cell_errors (line 197) | def test_to_ui_json_grid_includes_cell_errors(self):
  class TestSheetToUIJsonMetaData (line 224) | class TestSheetToUIJsonMetaData(unittest.TestCase):
    method test_to_ui_json_meta_data_zero_size (line 226) | def test_to_ui_json_meta_data_zero_size(self):
    method test_to_ui_json_meta_data_ten_by_five_empty (line 232) | def test_to_ui_json_meta_data_ten_by_five_empty(self):
    method test_to_ui_json_meta_data_includes_worksheet_console_text (line 238) | def test_to_ui_json_meta_data_includes_worksheet_console_text(self):
    method test_to_ui_json_meta_data_includes_columns_widths (line 250) | def test_to_ui_json_meta_data_includes_columns_widths(self):
    method test_to_ui_json_meta_data_includes_usercode_errors (line 262) | def test_to_ui_json_meta_data_includes_usercode_errors(self):

FILE: dirigible/sheet/tests/test_views.py
  class SheetViewTestCase (line 39) | class SheetViewTestCase(TransactionTestCase, ResolverTestCase):
    method assertMockUpdaterCalledOnceWithWorksheet (line 42) | def assertMockUpdaterCalledOnceWithWorksheet(
  function set_up_view_test (line 60) | def set_up_view_test(self):
  function create_view_security_test (line 69) | def create_view_security_test(
  class ImportXLSSecurityTest (line 141) | class ImportXLSSecurityTest(SheetViewTestCase):
    method test_view_login_required (line 146) | def test_view_login_required(self):
    method test_cannot_upload_to_another_users_dashboard (line 159) | def test_cannot_upload_to_another_users_dashboard(self):
  class ImportXLSTest (line 170) | class ImportXLSTest(SheetViewTestCase):
    method test_import_xls_creates_sheets_for_non_empty_worksheets_using_tempfiles (line 177) | def test_import_xls_creates_sheets_for_non_empty_worksheets_using_temp...
    method test_import_xls_closes_and_deletes_tempfile (line 228) | def test_import_xls_closes_and_deletes_tempfile(self, mock_os, mock_mk...
    method test_import_xls_imports_values_and_calls_calculate_on_each_sheet (line 258) | def test_import_xls_imports_values_and_calls_calculate_on_each_sheet(
    method test_import_xls_reports_success_on_exception_from_calculate (line 325) | def test_import_xls_reports_success_on_exception_from_calculate(
  class ImportCSVTest (line 365) | class ImportCSVTest(SheetViewTestCase):
    method test_import_csv_should_import_csv_and_update_sheet_with_version_check (line 371) | def test_import_csv_should_import_csv_and_update_sheet_with_version_ch...
    method test_import_csv_handles_null_file (line 432) | def test_import_csv_handles_null_file(self, mock_import_csv_form):
    method test_view_uses_and_handles_errors_from_worksheet_from_csv (line 453) | def test_view_uses_and_handles_errors_from_worksheet_from_csv(
    method test_view_calls_calculate_view_after_update_sheet (line 488) | def test_view_calls_calculate_view_after_update_sheet(
  class ExportCSVTest (line 515) | class ExportCSVTest(SheetViewTestCase):
    method test_export_excel_csv_should_produce_csv_with_correct_http_headers_and_content (line 521) | def test_export_excel_csv_should_produce_csv_with_correct_http_headers...
    method test_export_unicode_csv_should_produce_csv_with_correct_http_headers_and_content (line 549) | def test_export_unicode_csv_should_produce_csv_with_correct_http_heade...
    method test_export_excel_csv_handles_encoding_error_and_returns_message (line 576) | def test_export_excel_csv_handles_encoding_error_and_returns_message(s...
    method test_export_csv_allows_other_users_to_view_public_sheets (line 590) | def test_export_csv_allows_other_users_to_view_public_sheets(self):
    method test_export_csv_allows_anonymous_user_to_view_public_sheets (line 606) | def test_export_csv_allows_anonymous_user_to_view_public_sheets(self):
  class CopySheetTest (line 628) | class CopySheetTest(SheetViewTestCase):
    method test_copy_sheet_allows_other_users_to_copy_public_sheets (line 632) | def test_copy_sheet_allows_other_users_to_copy_public_sheets(self):
    method test_copy_sheet_requires_login_for_anonymous_user (line 666) | def test_copy_sheet_requires_login_for_anonymous_user(self):
  class PageViewTest (line 691) | class PageViewTest(SheetViewTestCase):
    method test_page_should_return_response_for_logged_in_owner (line 695) | def test_page_should_return_response_for_logged_in_owner(self):
    method test_page_should_render_template_with_correct_stuff_before_setting_userprofile_flag (line 704) | def test_page_should_render_template_with_correct_stuff_before_setting...
    method test_view_should_send_welcome_email_if_new_user (line 738) | def test_view_should_send_welcome_email_if_new_user(
    method test_page_allows_other_users_to_view_public_sheets (line 760) | def test_page_allows_other_users_to_view_public_sheets(self, mock_rend...
    method test_page_allows_anonymous_user_to_view_public_sheets (line 778) | def test_page_allows_anonymous_user_to_view_public_sheets(self, mock_r...
  class SetCellFormulaTest (line 799) | class SetCellFormulaTest(SheetViewTestCase):
    method test_view_should_set_cell_formula_and_update_sheet_with_version_check (line 804) | def test_view_should_set_cell_formula_and_update_sheet_with_version_ch...
    method test_other_users_cant_scf_even_on_public_worksheets (line 834) | def test_other_users_cant_scf_even_on_public_worksheets(self):
  class ClearCellsTest (line 862) | class ClearCellsTest(SheetViewTestCase):
    method test_view_should_clear_range_given_and_update_sheet_with_version_check (line 867) | def test_view_should_clear_range_given_and_update_sheet_with_version_c...
    method test_view_should_return_ok_if_successful (line 896) | def test_view_should_return_ok_if_successful(
    method test_view_should_return_fail_if_update_fails (line 910) | def test_view_should_return_fail_if_update_fails(
  class SetSheetUsercodeTest (line 929) | class SetSheetUsercodeTest(SheetViewTestCase):
    method test_view_should_set_sheet_usercode_and_updates_version (line 934) | def test_view_should_set_sheet_usercode_and_updates_version(self, mock...
    method test_view_set_sheet_usercode_fixes_windows_line_endings (line 949) | def test_view_set_sheet_usercode_fixes_windows_line_endings(self):
  class SetSheetSecuritySettingsTest (line 972) | class SetSheetSecuritySettingsTest(SheetViewTestCase):
    method test_view_should_set_sheet_security_settings (line 977) | def test_view_should_set_sheet_security_settings(self, mock_get_object):
  class SetSheetNameTest (line 1019) | class SetSheetNameTest(SheetViewTestCase):
    method test_view_should_set_sheet_name (line 1024) | def test_view_should_set_sheet_name(self, mock_get_object):
    method test_view_should_escape_naughty_characters_in_sheet_name (line 1052) | def test_view_should_escape_naughty_characters_in_sheet_name(self):
  class SetColumnWidthsTest (line 1066) | class SetColumnWidthsTest(SheetViewTestCase):
    method test_view_should_set_column_widths_and_save (line 1071) | def test_view_should_set_column_widths_and_save(self, mock_get_object):
  class CalculateTest (line 1097) | class CalculateTest(SheetViewTestCase):
    method test_view_should_use_managed_transaction_and_update_sheet_with_version_check (line 1104) | def test_view_should_use_managed_transaction_and_update_sheet_with_ver...
    method test_view_response_if_update_sheet_with_version_check_fails (line 1137) | def test_view_response_if_update_sheet_with_version_check_fails(
    method test_view_merges_any_minor_changes_using_transaction (line 1157) | def test_view_merges_any_minor_changes_using_transaction(
    method test_view_rolls_back_and_reraises_if_sheet_calculate_raises_with_uncommitted_changes (line 1201) | def test_view_rolls_back_and_reraises_if_sheet_calculate_raises_with_u...
    method test_view_rolls_back_and_reraises_if_get_object_raises_with_uncommitted_changes (line 1244) | def test_view_rolls_back_and_reraises_if_get_object_raises_with_uncomm...
  class GetJsonGridDataForUITest (line 1285) | class GetJsonGridDataForUITest(SheetViewTestCase):
    method test_returns_json_grid_data_for_range_using_get_object_or_404_if_range_specified (line 1292) | def test_returns_json_grid_data_for_range_using_get_object_or_404_if_r...
    method test_view_allows_other_users_to_view_public_sheets (line 1311) | def test_view_allows_other_users_to_view_public_sheets(self):
    method test_view_allows_anonymous_user_to_view_public_sheets (line 1325) | def test_view_allows_anonymous_user_to_view_public_sheets(self):
  class GetJsonMetaDataForUITest (line 1344) | class GetJsonMetaDataForUITest(SheetViewTestCase):
    method test_get_json_meta_data_for_ui_should_return_unrecalculated_sheet_to_ui_json_using_get_object_or_404 (line 1350) | def test_get_json_meta_data_for_ui_should_return_unrecalculated_sheet_...
    method test_view_allows_other_users_to_view_public_sheets (line 1368) | def test_view_allows_other_users_to_view_public_sheets(self):
    method test_view_allows_anonymous_user_to_view_public_sheets (line 1382) | def test_view_allows_anonymous_user_to_view_public_sheets(self):
  class VersionUpdatesSecurityTest (line 1397) | class VersionUpdatesSecurityTest(SheetViewTestCase):
  class VersionUpdatesTest (line 1402) | class VersionUpdatesTest(SheetViewTestCase):
    method test_all_views_considered_for_version_updates (line 1419) | def test_all_views_considered_for_version_updates(self):
    method test_update_sheet_with_version_check_should_update_increment_version_and_return_true_if_no_change (line 1500) | def test_update_sheet_with_version_check_should_update_increment_versi...
    method test_update_sheet_with_version_check_can_also_update_usercode (line 1517) | def test_update_sheet_with_version_check_can_also_update_usercode(self):
    method test_update_sheet_with_version_check_returns_false_and_doesnt_update_if_sheet_changed_in_database (line 1530) | def test_update_sheet_with_version_check_returns_false_and_doesnt_upda...
  class ClipboardViewTest (line 1564) | class ClipboardViewTest(SheetViewTestCase):
    method test_copy_gets_formulas_or_formatted_values_and_populates_clipboard (line 1568) | def test_copy_gets_formulas_or_formatted_values_and_populates_clipboar...
    method test_paste_offsets_range_and_updates_sheet_with_version_check (line 1614) | def test_paste_offsets_range_and_updates_sheet_with_version_check(
    method test_failing_paste_returns_failure_message_and_doesnt_save_clipboard (line 1651) | def test_failing_paste_returns_failure_message_and_doesnt_save_clipboard(
    method test_cut_populates_and_saves_clipboard_then_removes_cells_and_saves_sheet (line 1670) | def test_cut_populates_and_saves_clipboard_then_removes_cells_and_save...
    method test_failing_cut_returns_failure_message_and_doesnt_save_clipboard (line 1738) | def test_failing_cut_returns_failure_message_and_doesnt_save_clipboard(
    method test_copy_then_paste_both_save_clipboard_appropriately (line 1756) | def test_copy_then_paste_both_save_clipboard_appropriately(self, mockC...
    method test_cut_then_paste_to_same_sheet (line 1773) | def test_cut_then_paste_to_same_sheet(self, mockClipboard):
  class MetaSecurityTest (line 1791) | class MetaSecurityTest(SheetViewTestCase):
    method test_security_classes_exist (line 1792) | def test_security_classes_exist(self):

FILE: dirigible/sheet/tests/test_views_api_0_1.py
  class CalculateAndGetJsonForApiViewTest (line 29) | class CalculateAndGetJsonForApiViewTest(
    method tearDown (line 35) | def tearDown(self):
    method test_should_return_404_if_sheet_owner_does_not_match_username_from_url (line 39) | def test_should_return_404_if_sheet_owner_does_not_match_username_from...
    method test_returns_403_if_neither_private_nor_api_keys_provided (line 47) | def test_returns_403_if_neither_private_nor_api_keys_provided(self):
    method test_returns_403_if_incorrect_private_key_provided (line 52) | def test_returns_403_if_incorrect_private_key_provided(self):
    method test_works_if_correct_private_key_provided (line 59) | def test_works_if_correct_private_key_provided(self):
    method test_erm_checks_private_key_using_correct_filter (line 67) | def test_erm_checks_private_key_using_correct_filter(
    method test_ignores_old_private_key_things (line 85) | def test_ignores_old_private_key_things(self):
    method test_403s_if_no_private_key_and_api_access_not_allowed_even_if_correct_api_key_provided (line 104) | def test_403s_if_no_private_key_and_api_access_not_allowed_even_if_cor...
    method test_403s_if_api_access_allowed_but_incorrect_api_key_provided (line 114) | def test_403s_if_api_access_allowed_but_incorrect_api_key_provided(self):
    method test_works_if_correct_api_key_provided_and_access_allowed (line 123) | def test_works_if_correct_api_key_provided_and_access_allowed(self):
    method test_should_call_sheet_calculate_with_transaction (line 135) | def test_should_call_sheet_calculate_with_transaction(
    method test_rolls_back_and_reraises_if_get_object_raises_with_uncommitted_changes (line 163) | def test_rolls_back_and_reraises_if_get_object_raises_with_uncommitted...
    method test_adds_access_control_header (line 198) | def test_adds_access_control_header(
    method test_commits_transaction_even_on_sheet_calculate_exception (line 222) | def test_commits_transaction_even_on_sheet_calculate_exception(
    method test_should_return_errors_and_no_values_if_unjsonify_worksheet_result_has_errors (line 241) | def test_should_return_errors_and_no_values_if_unjsonify_worksheet_res...
    method die (line 271) | def die(*_):
    method test_should_handle_cell_formula_overrides_from_POST (line 276) | def test_should_handle_cell_formula_overrides_from_POST(self, mock_get...
    method test_should_handle_cell_formula_overrides_from_GET (line 320) | def test_should_handle_cell_formula_overrides_from_GET(self, mock_get_...
  class TestSheetToValueOnlyJson (line 364) | class TestSheetToValueOnlyJson(unittest.TestCase):
    method test_sheet_to_value_only_json_for_empty_worksheet (line 366) | def test_sheet_to_value_only_json_for_empty_worksheet(self):
    method test_sheet_to_value_only_json_with_content (line 372) | def test_sheet_to_value_only_json_with_content(self):
    method test_sheet_to_value_only_json_does_not_include_errors (line 400) | def test_sheet_to_value_only_json_does_not_include_errors(self):
    method test_sheet_to_value_only_json_non_string_cell_values (line 418) | def test_sheet_to_value_only_json_non_string_cell_values(self):

FILE: dirigible/sheet/tests/test_worksheet.py
  class WorksheetToCsvTest (line 29) | class WorksheetToCsvTest(ResolverTestCase):
    method test_should_use_stringio_and_return_result (line 33) | def test_should_use_stringio_and_return_result(self, mock_stringio_cla...
    method test_should_handle_empty_worksheet (line 50) | def test_should_handle_empty_worksheet(self, mock_csv):
    method test_should_convert_unicode_to_windows_1252 (line 59) | def test_should_convert_unicode_to_windows_1252(self):
    method test_raises_on_attempting_to_encode_nonwestern_chars_to_excel_format (line 75) | def test_raises_on_attempting_to_encode_nonwestern_chars_to_excel_form...
    method test_handles_cell_values_set_to_non_ascii_bytes (line 85) | def test_handles_cell_values_set_to_non_ascii_bytes(self):
    method test_can_convert_unicode_to_utf8 (line 97) | def test_can_convert_unicode_to_utf8(self):
    method test_should_process_contents_in_raster_order (line 111) | def test_should_process_contents_in_raster_order(self, mock_csv):
    method test_should_include_everything_from_A1_outwards (line 133) | def test_should_include_everything_from_A1_outwards(self, mock_csv):
  class WorksheetJSONificationTest (line 151) | class WorksheetJSONificationTest(ResolverTestCase):
    method test_empty_worksheet_to_json (line 153) | def test_empty_worksheet_to_json(self):
    method test_worksheet_to_json_remembers_to_close_stringIO_stream (line 167) | def test_worksheet_to_json_remembers_to_close_stringIO_stream(self, mo...
    method test_worksheet_with_data_to_json (line 174) | def test_worksheet_with_data_to_json(self):
    method test_dependencies_get_put_in_json_as_array_of_arrays (line 238) | def test_dependencies_get_put_in_json_as_array_of_arrays(self):
    method test_nan_values_are_ignored (line 262) | def test_nan_values_are_ignored(self):
    method test_empty_worksheet_from_json (line 280) | def test_empty_worksheet_from_json(self):
    method test_worksheet_with_data_from_json (line 295) | def test_worksheet_with_data_from_json(self):
    method test_worksheet_from_json_uses_json (line 370) | def test_worksheet_from_json_uses_json(self, mock_json):
  class WorksheetTest (line 377) | class WorksheetTest(unittest.TestCase):
    method test_initialise (line 379) | def test_initialise(self):
    method test_repr (line 387) | def test_repr(self):
    method test_equality (line 394) | def test_equality(self):
    method test_append_console_text (line 414) | def test_append_console_text(self):
    method test_to_location (line 456) | def test_to_location(self):
    method test_setitem_on_locations_should_accept_cell_instances (line 473) | def test_setitem_on_locations_should_accept_cell_instances(self):
    method test_setitem_on_locations_should_reject_non_cell_instances (line 484) | def test_setitem_on_locations_should_reject_non_cell_instances(self):
    method test_setitem_on_non_locations_raises_keyerror (line 494) | def test_setitem_on_non_locations_raises_keyerror(self):
    method test_getitem_creates_cells (line 502) | def test_getitem_creates_cells(self):
    method test_get_item_does_not_create_cells_for_random_strings (line 510) | def test_get_item_does_not_create_cells_for_random_strings(self):
    method test_getitem_should_use_to_location_result_if_it_is_not_none (line 518) | def test_getitem_should_use_to_location_result_if_it_is_not_none(self):
    method test_getitem_should_use_original_key_if_to_location_gives_none (line 529) | def test_getitem_should_use_original_key_if_to_location_gives_none(self):
    method test_getattr_should_delegate_to_getitem (line 540) | def test_getattr_should_delegate_to_getitem(self):
    method test_setattr_should_delegate_to_setitem_if_attr_name_is_valid_cell_name (line 551) | def test_setattr_should_delegate_to_setitem_if_attr_name_is_valid_cell...
    method test_setattr_should_not_delegate_to_setitem_if_attr_name_is_not_valid_cell_name (line 570) | def test_setattr_should_not_delegate_to_setitem_if_attr_name_is_not_va...
    method test_set_cell_formula_with_value_should_update_internal_contents (line 580) | def test_set_cell_formula_with_value_should_update_internal_contents(s...
    method test_set_cell_formula_with_empty_string_should_clear_internal_contents_if_they_exist (line 586) | def test_set_cell_formula_with_empty_string_should_clear_internal_cont...
    method test_set_cell_formula_with_empty_string_should_do_nothing_if_no_preexisting_internal_contents (line 593) | def test_set_cell_formula_with_empty_string_should_do_nothing_if_no_pr...
    method test_clear_values_clears_values_and_formatted_values_and_errors (line 599) | def test_clear_values_clears_values_and_formatted_values_and_errors(se...
    method test_clear_values_deletes_cells_with_no_formula (line 620) | def test_clear_values_deletes_cells_with_no_formula(self):
    method test_clear_values_deletes_cells_with_empty_formula (line 629) | def test_clear_values_deletes_cells_with_empty_formula(self):
    method test_iteration_yields_cells (line 638) | def test_iteration_yields_cells(self):
    method test_add_console_text_is_thread_safe (line 647) | def test_add_console_text_is_thread_safe(self):
    method test_getting_bounds_on_empty_sheet_should_return_none (line 673) | def test_getting_bounds_on_empty_sheet_should_return_none(self):
    method test_getting_bounds_with_one_cell_should_return_bounds (line 678) | def test_getting_bounds_with_one_cell_should_return_bounds(self):
    method test_getting_bounds_with_two_cells_should_return_bounds (line 686) | def test_getting_bounds_with_two_cells_should_return_bounds(self):
    method test_setting_bounds_should_fail (line 695) | def test_setting_bounds_should_fail(self):
  class TestWorksheetCellRangeConstructor (line 702) | class TestWorksheetCellRangeConstructor(ResolverTestCase):
    method test_two_tuple_parameters (line 704) | def test_two_tuple_parameters(self):
    method test_single_string_parameter_uses_formula_notation (line 712) | def test_single_string_parameter_uses_formula_notation(self):
    method test_double_string_parameters_use_a1_notation (line 733) | def test_double_string_parameters_use_a1_notation(self):
    method test_mixed_parameters (line 760) | def test_mixed_parameters(self):
  class BoundsTest (line 782) | class BoundsTest(ResolverTestCase):
    method test_bounds_acts_like_tuple (line 784) | def test_bounds_acts_like_tuple(self):
    method test_bounds_has_sweet_properties (line 791) | def test_bounds_has_sweet_properties(self):
    method test_bounds_barfs_on_wrong_number_of_parameters (line 799) | def test_bounds_barfs_on_wrong_number_of_parameters(self):

FILE: dirigible/sheet/tests/utils/test_cell_name_utils.py
  class CellNameUtilsTest (line 19) | class CellNameUtilsTest(unittest.TestCase):
    method testColumnNameTo (line 21) | def testColumnNameTo(self):
    method testColumnIndexTo (line 44) | def testColumnIndexTo(self):
    method testColRowNames (line 58) | def testColRowNames(self):
    method testCoordinatesToCell (line 69) | def testCoordinatesToCell(self):
    method testCoordinatesToCell2 (line 78) | def testCoordinatesToCell2(self):
    method test_coordinates_to_cell_name_bad (line 86) | def test_coordinates_to_cell_name_bad(self):
    method testCellNameTo (line 95) | def testCellNameTo(self):
    method testAbsoluteCellName (line 116) | def testAbsoluteCellName(self):
    method test_cell_ref_as_string_to_coordinates (line 160) | def test_cell_ref_as_string_to_coordinates(self):
    method test_cell_range_as_string_to_coordinates (line 170) | def test_cell_range_as_string_to_coordinates(self):

FILE: dirigible/sheet/tests/utils/test_interruptable_thread.py
  class TestInterruptableThread (line 14) | class TestInterruptableThread(unittest.TestCase):
    method test_interruptable_thread_is (line 16) | def test_interruptable_thread_is(self):

FILE: dirigible/sheet/tests/utils/test_string_utils.py
  class StringUtilsTest (line 17) | class StringUtilsTest(unittest.TestCase):
    method test_get_rstripped_part (line 19) | def test_get_rstripped_part(self):
    method test_get_lstripped_part (line 25) | def test_get_lstripped_part(self):
    method test_double_quote_repr (line 32) | def test_double_quote_repr(self):
    method testCorrectCase (line 38) | def testCorrectCase(self):

FILE: dirigible/sheet/ui_jsonifier.py
  function sheet_to_ui_json_meta_data (line 8) | def sheet_to_ui_json_meta_data(sheet, worksheet):
  function sheet_to_ui_json_grid_data (line 26) | def sheet_to_ui_json_grid_data(worksheet, rnge):

FILE: dirigible/sheet/utils/cell_name_utils.py
  function column_name_to_index (line 10) | def column_name_to_index(colName):
  function column_index_to_name (line 22) | def column_index_to_name(index):
  function _col_row_names_to_coordinates (line 35) | def _col_row_names_to_coordinates(col, row):
  function coordinates_to_cell_name (line 45) | def coordinates_to_cell_name(col, row, colAbsolute=False, rowAbsolute=Fa...
  function cell_name_to_coordinates (line 53) | def cell_name_to_coordinates(cellName):
  function cell_ref_as_string_to_coordinates (line 86) | def cell_ref_as_string_to_coordinates(cell_ref):
  function cell_range_as_string_to_coordinates (line 98) | def cell_range_as_string_to_coordinates(cell_range_string):

FILE: dirigible/sheet/utils/interruptable_thread.py
  class TimeoutException (line 7) | class TimeoutException(Exception):
  class InterruptableThread (line 10) | class InterruptableThread(Thread):
    method _get_thread_id (line 12) | def _get_thread_id(self):
    method interrupt (line 21) | def interrupt(self):

FILE: dirigible/sheet/utils/string_utils.py
  function get_rstripped_part (line 5) | def get_rstripped_part(string):
  function get_lstripped_part (line 11) | def get_lstripped_part(string):
  function double_quote_repr_string (line 17) | def double_quote_repr_string(inString):
  function correct_case (line 24) | def correct_case(candidate, potentialMatches):

FILE: dirigible/sheet/views.py
  function fetch_users_sheet (line 37) | def fetch_users_sheet(view):
  function fetch_users_or_public_sheet (line 47) | def fetch_users_or_public_sheet(view):
  function rollback_on_exception (line 66) | def rollback_on_exception(view):
  function update_sheet_with_version_check (line 80) | def update_sheet_with_version_check(sheet, **kwargs):
  function import_xls (line 87) | def import_xls(request, username):
  function export_csv (line 124) | def export_csv(request, sheet, csv_format):
  function import_csv (line 151) | def import_csv(request, sheet):
  function copy_sheet (line 189) | def copy_sheet(request, sheet):
  function new_sheet (line 198) | def new_sheet(request):
  function page (line 209) | def page(request, sheet):
  function set_cell_formula (line 239) | def set_cell_formula(request, sheet):
  function clear_cells (line 255) | def clear_cells(request, sheet):
  function set_sheet_usercode (line 271) | def set_sheet_usercode(request, sheet):
  function set_sheet_name (line 281) | def set_sheet_name(request, sheet):
  function set_column_widths (line 289) | def set_column_widths(request, sheet):
  function set_sheet_security_settings (line 297) | def set_sheet_security_settings(request, sheet):
  function get_json_grid_data_for_ui (line 306) | def get_json_grid_data_for_ui(request, sheet):
  function get_json_meta_data_for_ui (line 312) | def get_json_meta_data_for_ui(request, sheet):
  function calculate (line 320) | def calculate(request, sheet):
  function clipboard (line 337) | def clipboard(request, sheet, action):

FILE: dirigible/sheet/views_api_0_1.py
  function calculate_and_get_json_for_api (line 21) | def calculate_and_get_json_for_api(request, username, sheet_id):
  function _sheet_to_value_only_json (line 78) | def _sheet_to_value_only_json(sheet_name, worksheet):

FILE: dirigible/sheet/worksheet.py
  class InvalidKeyError (line 22) | class InvalidKeyError(Exception):
  class Bounds (line 27) | class Bounds(tuple):
    method __init__ (line 29) | def __init__(self, (left, top, right, bottom)):
  function dump_cell_to_json_stream (line 34) | def dump_cell_to_json_stream(stream, col, row, cell):
  function worksheet_to_json (line 54) | def worksheet_to_json(worksheet):
  function worksheet_from_json (line 71) | def worksheet_from_json(json_string):
  function worksheet_to_csv (line 94) | def worksheet_to_csv(worksheet, encoding):
  function worksheet_from_excel (line 118) | def worksheet_from_excel(excel_sheet):
  class Worksheet (line 134) | class Worksheet(dict):
    method __init__ (line 136) | def __init__(self):
    method __getitem__ (line 143) | def __getitem__(self, key):
    method __setitem__ (line 151) | def __setitem__(self, key, item):
    method __getattr__ (line 162) | def __getattr__(self, name):
    method __setattr__ (line 170) | def __setattr__(self, name, value):
    method __repr__ (line 178) | def __repr__(self):
    method __eq__ (line 185) | def __eq__(self, other):
    method __ne__ (line 193) | def __ne__(self, other):
    method to_location (line 197) | def to_location(self, key):
    method add_console_text (line 210) | def add_console_text(self, error_text, log_type='error'):
    method set_cell_formula (line 217) | def set_cell_formula(self, col, row, formula):
    method clear_values (line 225) | def clear_values(self):
    method cell_range (line 239) | def cell_range(self, start_or_string_cellrange, end=None):
    method bounds (line 263) | def bounds(self):

FILE: dirigible/user/admin.py
  class UserProfileInline (line 15) | class UserProfileInline(admin.StackedInline):
  function has_seen_sheet_page (line 18) | def has_seen_sheet_page(user):
  class MyUserAdmin (line 23) | class MyUserAdmin(UserAdmin):

FILE: dirigible/user/forms.py
  class DirigibleRegistrationForm (line 8) | class DirigibleRegistrationForm(RegistrationForm):
    method __init__ (line 9) | def __init__(self, *args, **kwargs):

FILE: dirigible/user/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: dirigible/user/models.py
  function get_uid (line 10) | def get_uid():
  class OneTimePad (line 13) | class OneTimePad(models.Model):
  class UserProfile (line 19) | class UserProfile(models.Model):
  class AnonymousProfile (line 25) | class AnonymousProfile(object):

FILE: dirigible/user/tests/test_forms.py
  class DirigibleRegistrationFormTest (line 11) | class DirigibleRegistrationFormTest(ResolverTestCase):
    method test_is_registration_form (line 13) | def test_is_registration_form(self):
    method test_error_messages (line 18) | def test_error_messages(self):

FILE: dirigible/user/tests/test_models.py
  class TestOneTimePads (line 13) | class TestOneTimePads(ResolverTestCase):
    method test_OneTimePad_init (line 16) | def test_OneTimePad_init(self, mock_uuid4):
  class TestUserProfiles (line 28) | class TestUserProfiles(ResolverTestCase):
    method test_defaults (line 30) | def test_defaults(self):
    method test_save_new_user_creates_user_profile (line 35) | def test_save_new_user_creates_user_profile(self):
  class TestAnonymousUser (line 42) | class TestAnonymousUser(ResolverTestCase):
    method test_anonymous_user_has_a_profile (line 44) | def test_anonymous_user_has_a_profile(self):
    method test_anonymous_user_attrs (line 48) | def test_anonymous_user_attrs(self):
    method test_anonymous_profile_attrs (line 51) | def test_anonymous_profile_attrs(self):

FILE: dirigible/user/tests/test_views.py
  function set_up_view_test (line 24) | def set_up_view_test(self):
  class RedirectToFrontPageTest (line 33) | class RedirectToFrontPageTest(django.test.TestCase):
    method test_redirects_to_user_page_when_logged_in (line 37) | def test_redirects_to_user_page_when_logged_in(self):
  class UserDashboardSecurityTest (line 46) | class UserDashboardSecurityTest(django.test.TestCase):
    method test_view_login_required (line 50) | def test_view_login_required(self):
  class UserDashboardTest (line 63) | class UserDashboardTest(django.test.TestCase):
    method test_page_should_return_response_for_logged_in_owner (line 67) | def test_page_should_return_response_for_logged_in_owner(self):
    method test_userpage_has_list_of_sheets (line 72) | def test_userpage_has_list_of_sheets(self, mock_render_to_response):
  class ChangePasswordSecurityTest (line 89) | class ChangePasswordSecurityTest(django.test.TestCase):
    method test_view_should_raise_on_wrong_user (line 93) | def test_view_should_raise_on_wrong_user(self):
    method test_view_404_errors_should_be_indistinguishable (line 99) | def test_view_404_errors_should_be_indistinguishable(self):
    method test_view_login_required (line 120) | def test_view_login_required(self):
    method test_view_should_raise_if_nonexistent_user (line 133) | def test_view_should_raise_if_nonexistent_user(self):
  class ChangePasswordTest (line 137) | class ChangePasswordTest(django.test.TestCase):
    method test_change_password_with_empty_fields (line 141) | def test_change_password_with_empty_fields(self):
    method test_change_password_with_wrong_old_password (line 148) | def test_change_password_with_wrong_old_password(self):
    method test_change_password_with_differing_new_passwords (line 159) | def test_change_password_with_differing_new_passwords(self):
    method test_change_password_does (line 170) | def test_change_password_does(self):
  class RegistrationViewsTest (line 184) | class RegistrationViewsTest(ResolverTestCase):
    method test_register_puts_email_address_into_session_if_form_is_valid (line 188) | def test_register_puts_email_address_into_session_if_form_is_valid(sel...
    method test_copy_sheet_for_new_user_callback_copies_sheet_specified_in_next_url (line 210) | def test_copy_sheet_for_new_user_callback_copies_sheet_specified_in_ne...
    method test_register_doesnt_put_email_address_into_session_if_form_is_not_valid (line 229) | def test_register_doesnt_put_email_address_into_session_if_form_is_not...
    method test_register_delegates_to_django_registration_with_form (line 252) | def test_register_delegates_to_django_registration_with_form(self, moc...
    method test_register_provides_extra_context_only_if_its_provided (line 281) | def test_register_provides_extra_context_only_if_its_provided(self, mo...
    method test_registration_complete_renders_template_with_email_address_from_session (line 312) | def test_registration_complete_renders_template_with_email_address_fro...
    method test_registration_complete_renders_template_with_blank_email_address_if_none_in_session (line 333) | def test_registration_complete_renders_template_with_blank_email_addre...
  class MetaSecurityTest (line 352) | class MetaSecurityTest(django.test.TestCase):
    method test_security_classes_exist (line 353) | def test_security_classes_exist(self):

FILE: dirigible/user/views.py
  function copy_sheet_for_new_user_callback (line 16) | def copy_sheet_for_new_user_callback(next_url):
  function register (line 24) | def register(request):
  function registration_complete (line 43) | def registration_complete(request):
  function redirect_to_front_page (line 51) | def redirect_to_front_page(request):
  function user_dashboard (line 56) | def user_dashboard(request):
  function change_password (line 62) | def change_password(request, username):

FILE: documentation/BeautifulSoup.py
  function sob (line 107) | def sob(unicode, encoding):
  class PageElement (line 114) | class PageElement:
    method setup (line 118) | def setup(self, parent=None, previous=None):
    method replaceWith (line 130) | def replaceWith(self, replaceWith):
    method extract (line 144) | def extract(self):
    method _lastRecursiveChild (line 173) | def _lastRecursiveChild(self):
    method insert (line 180) | def insert(self, position, newChild):
    method append (line 240) | def append(self, tag):
    method findNext (line 244) | def findNext(self, name=None, attrs={}, text=None, **kwargs):
    method findAllNext (line 249) | def findAllNext(self, name=None, attrs={}, text=None, limit=None,
    method findNextSibling (line 256) | def findNextSibling(self, name=None, attrs={}, text=None, **kwargs):
    method findNextSiblings (line 262) | def findNextSiblings(self, name=None, attrs={}, text=None, limit=None,
    method findPrevious (line 270) | def findPrevious(self, name=None, attrs={}, text=None, **kwargs):
    method findAllPrevious (line 275) | def findAllPrevious(self, name=None, attrs={}, text=None, limit=None,
    method findPreviousSibling (line 283) | def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs):
    method findPreviousSiblings (line 289) | def findPreviousSiblings(self, name=None, attrs={}, text=None,
    method findParent (line 297) | def findParent(self, name=None, attrs={}, **kwargs):
    method findParents (line 308) | def findParents(self, name=None, attrs={}, limit=None, **kwargs):
    method _findOne (line 318) | def _findOne(self, method, name, attrs, text, **kwargs):
    method _findAll (line 325) | def _findAll(self, name, attrs, text, limit, generator, **kwargs):
    method nextGenerator (line 350) | def nextGenerator(self):
    method nextSiblingGenerator (line 356) | def nextSiblingGenerator(self):
    method previousGenerator (line 362) | def previousGenerator(self):
    method previousSiblingGenerator (line 368) | def previousSiblingGenerator(self):
    method parentGenerator (line 374) | def parentGenerator(self):
    method substituteEncoding (line 381) | def substituteEncoding(self, str, encoding=None):
    method toEncoding (line 385) | def toEncoding(self, s, encoding=None):
  class NavigableString (line 403) | class NavigableString(unicode, PageElement):
    method __new__ (line 405) | def __new__(cls, value):
    method __getnewargs__ (line 417) | def __getnewargs__(self):
    method __getattr__ (line 420) | def __getattr__(self, attr):
    method encode (line 429) | def encode(self, encoding=DEFAULT_OUTPUT_ENCODING):
    method decodeGivenEventualEncoding (line 432) | def decodeGivenEventualEncoding(self, eventualEncoding):
  class CData (line 435) | class CData(NavigableString):
    method decodeGivenEventualEncoding (line 437) | def decodeGivenEventualEncoding(self, eventualEncoding):
  class ProcessingInstruction (line 440) | class ProcessingInstruction(NavigableString):
    method decodeGivenEventualEncoding (line 442) | def decodeGivenEventualEncoding(self, eventualEncoding):
  class Comment (line 448) | class Comment(NavigableString):
    method decodeGivenEventualEncoding (line 449) | def decodeGivenEventualEncoding(self, eventualEncoding):
  class Declaration (line 452) | class Declaration(NavigableString):
    method decodeGivenEventualEncoding (line 453) | def decodeGivenEventualEncoding(self, eventualEncoding):
  class Tag (line 456) | class Tag(PageElement):
    method _invert (line 460) | def _invert(h):
    method _convertEntities (line 475) | def _convertEntities(self, match):
    method __init__ (line 500) | def __init__(self, parser, name, attrs=None, parent=None,
    method get (line 529) | def get(self, key, default=None):
    method has_key (line 535) | def has_key(self, key):
    method __getitem__ (line 538) | def __getitem__(self, key):
    method __iter__ (line 543) | def __iter__(self):
    method __len__ (line 547) | def __len__(self):
    method __contains__ (line 551) | def __contains__(self, x):
    method __nonzero__ (line 554) | def __nonzero__(self):
    method __setitem__ (line 558) | def __setitem__(self, key, value):
    method __delitem__ (line 572) | def __delitem__(self, key):
    method __call__ (line 583) | def __call__(self, *args, **kwargs):
    method __getattr__ (line 589) | def __getattr__(self, tag):
    method __eq__ (line 597) | def __eq__(self, other):
    method __ne__ (line 610) | def __ne__(self, other):
    method __repr__ (line 615) | def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
    method _sub_entity (line 623) | def _sub_entity(self, x):
    method __unicode__ (line 628) | def __unicode__(self):
    method __str__ (line 631) | def __str__(self):
    method encode (line 634) | def encode(self, encoding=DEFAULT_OUTPUT_ENCODING,
    method decode (line 638) | def decode(self, prettyPrint=False, indentLevel=0,
    method decompose (line 723) | def decompose(self):
    method prettify (line 733) | def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
    method encodeContents (line 736) | def encodeContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
    method decodeContents (line 740) | def decodeContents(self, prettyPrint=False, indentLevel=0,
    method find (line 763) | def find(self, name=None, attrs={}, recursive=True, text=None,
    method findAll (line 774) | def findAll(self, name=None, attrs={}, recursive=True, text=None,
    method fetchText (line 795) | def fetchText(self, text=None, recursive=True, limit=None):
    method firstText (line 798) | def firstText(self, text=None, recursive=True):
    method renderContents (line 802) | def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
    method _getAttrMap (line 812) | def _getAttrMap(self):
    method recursiveChildGenerator (line 822) | def recursiveChildGenerator(self):
    method childGenerator (line 831) | def childGenerator(self):
  class SoupStrainer (line 841) | class SoupStrainer:
    method __init__ (line 845) | def __init__(self, name=None, attrs={}, text=None, **kwargs):
    method __str__ (line 859) | def __str__(self):
    method searchTag (line 865) | def searchTag(self, markupName=None, markupAttrs={}):
    method search (line 902) | def search(self, markup):
    method _matches (line 928) | def _matches(self, markup, matchAgainst):
  class ResultSet (line 961) | class ResultSet(list):
    method __init__ (line 964) | def __init__(self, source):
  function isList (line 970) | def isList(l):
  function isString (line 976) | def isString(s):
  function buildTagMap (line 984) | def buildTagMap(default, *args):
  class HTMLParserBuilder (line 1005) | class HTMLParserBuilder(HTMLParser):
    method __init__ (line 1007) | def __init__(self, soup):
    method handle_starttag (line 1013) | def handle_starttag(self, name, attrs):
    method handle_endtag (line 1019) | def handle_endtag(self, name):
    method handle_data (line 1022) | def handle_data(self, content):
    method _toStringSubclass (line 1025) | def _toStringSubclass(self, text, subclass):
    method handle_pi (line 1032) | def handle_pi(self, text):
    method handle_comment (line 1040) | def handle_comment(self, text):
    method handle_charref (line 1044) | def handle_charref(self, ref):
    method handle_entityref (line 1052) | def handle_entityref(self, ref):
    method handle_decl (line 1095) | def handle_decl(self, data):
    method parse_declaration (line 1099) | def parse_declaration(self, i):
  class BeautifulStoneSoup (line 1120) | class BeautifulStoneSoup(Tag):
    method __init__ (line 1164) | def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
    method _feed (line 1236) | def _feed(self, inDocumentEncoding=None, isHTML=False):
    method isSelfClosingTag (line 1269) | def isSelfClosingTag(self, name):
    method reset (line 1275) | def reset(self):
    method popTag (line 1285) | def popTag(self):
    method pushTag (line 1299) | def pushTag(self, tag):
    method endData (line 1306) | def endData(self, containerClass=NavigableString):
    method _popToTag (line 1329) | def _popToTag(self, name, inclusivePop=True):
    method _smartPop (line 1351) | def _smartPop(self, name):
    method unknown_starttag (line 1397) | def unknown_starttag(self, name, attrs, selfClosing=0):
    method unknown_endtag (line 1427) | def unknown_endtag(self, name):
    method handle_data (line 1440) | def handle_data(self, data):
    method extractCharsetFromMeta (line 1443) | def extractCharsetFromMeta(self, attrs):
  class BeautifulSoup (line 1447) | class BeautifulSoup(BeautifulStoneSoup):
    method __init__ (line 1495) | def __init__(self, *args, **kwargs):
    method extractCharsetFromMeta (line 1553) | def extractCharsetFromMeta(self, attrs):
  class StopParsing (line 1601) | class StopParsing(Exception):
  class ICantBelieveItsBeautifulSoup (line 1604) | class ICantBelieveItsBeautifulSoup(BeautifulSoup):
  class MinimalSoup (line 1640) | class MinimalSoup(BeautifulSoup):
  class BeautifulSOAP (line 1653) | class BeautifulSOAP(BeautifulStoneSoup):
    method popTag (line 1673) | def popTag(self):
  class RobustXMLParser (line 1692) | class RobustXMLParser(BeautifulStoneSoup):
  class RobustHTMLParser (line 1694) | class RobustHTMLParser(BeautifulSoup):
  class RobustWackAssHTMLParser (line 1696) | class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
  class RobustInsanelyWackAssHTMLParser (line 1698) | class RobustInsanelyWackAssHTMLParser(MinimalSoup):
  class SimplifyingSOAPParser (line 1700) | class SimplifyingSOAPParser(BeautifulSOAP):
  class UnicodeDammit (line 1734) | class UnicodeDammit:
    method __init__ (line 1747) | def __init__(self, markup, overrideEncodings=[],
    method _subMSChar (line 1781) | def _subMSChar(self, match):
    method _convertFrom (line 1795) | def _convertFrom(self, proposed):
    method _toUnicode (line 1823) | def _toUnicode(self, data, encoding):
    method _detectEncoding (line 1848) | def _detectEncoding(self, xml_data, isHTML=False):
    method find_codec (line 1918) | def find_codec(self, charset):
    method _codec (line 1924) | def _codec(self, charset):
    method _ebcdic_to_ascii (line 1935) | def _ebcdic_to_ascii(self, s):
Condensed preview — 403 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,489K chars).
[
  {
    "path": ".gitignore",
    "chars": 36,
    "preview": "*.pyc\npython/dirigible/dirigible.db\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1108,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Resolver Systems Ltd, PythonAnywhere LLP\n\nPermission is hereby granted, free o"
  },
  {
    "path": "README.md",
    "chars": 3811,
    "preview": "Dirigible, the web-based Pythonic Spreadsheet\n=============================================\n\nThis is the source code fro"
  },
  {
    "path": "dirigible/.gitignore",
    "chars": 27,
    "preview": "db.sqlite3\nfts/screendumps\n"
  },
  {
    "path": "dirigible/dirigible/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/dirigible/settings.py",
    "chars": 2254,
    "preview": "\"\"\"\nDjango settings for dirigible project.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/dev"
  },
  {
    "path": "dirigible/dirigible/test_utils.py",
    "chars": 2110,
    "preview": "# Copyright (c) 2005-2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\ntry:\n    import unittest2 as unit"
  },
  {
    "path": "dirigible/dirigible/urls.py",
    "chars": 1638,
    "preview": "import os\n\nfrom django.conf.urls import patterns, include, url\nfrom django.contrib import admin\nfrom django.conf import "
  },
  {
    "path": "dirigible/dirigible/wsgi.py",
    "chars": 393,
    "preview": "\"\"\"\nWSGI config for dirigible project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\n"
  },
  {
    "path": "dirigible/featured_sheet/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/featured_sheet/admin.py",
    "chars": 199,
    "preview": "# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\nfrom featured_sheet.models import Featu"
  },
  {
    "path": "dirigible/featured_sheet/models.py",
    "chars": 409,
    "preview": "# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom django.db import models\n\nfrom she"
  },
  {
    "path": "dirigible/featured_sheet/templates/featured_sheets.html",
    "chars": 1271,
    "preview": "{% extends \"info_page.html\" %}\n\n{% block title %}\n    Featured Sheets: Dirigible\n{% endblock %}\n\n{% block head %}\n    {{"
  },
  {
    "path": "dirigible/featured_sheet/tests/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "dirigible/featured_sheet/tests/test_models.py",
    "chars": 1831,
    "preview": "# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\nfrom django.contrib.auth.models import "
  },
  {
    "path": "dirigible/featured_sheet/views.py",
    "chars": 82,
    "preview": "# Copyright (c) 2011 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\n"
  },
  {
    "path": "dirigible/feedback/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/feedback/models.py",
    "chars": 111,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom django.db import models\n"
  },
  {
    "path": "dirigible/feedback/tests/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "dirigible/feedback/tests/test_views.py",
    "chars": 1313,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom mock import patch\nfrom textwrap i"
  },
  {
    "path": "dirigible/feedback/urls.py",
    "chars": 266,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom django.conf.urls import *\n\nfrom f"
  },
  {
    "path": "dirigible/feedback/views.py",
    "chars": 695,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom textwrap import dedent\n\nfrom djan"
  },
  {
    "path": "dirigible/fts/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/fts/screendumps/placeholder",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/fts/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/fts/tests/functionaltest.py",
    "chars": 37142,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nfrom __future__ import print_function\n\nfrom contextli"
  },
  {
    "path": "dirigible/fts/tests/test_2521_CodeEditor.py",
    "chars": 7634,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom selenium.webdriver.common.keys import Keys\nfrom"
  },
  {
    "path": "dirigible/fts/tests/test_2525_LoginLogout.py",
    "chars": 9829,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom urlparse import urlparse\n\nfrom functionaltest i"
  },
  {
    "path": "dirigible/fts/tests/test_2528_CreateEditSheet.py",
    "chars": 7761,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom selenium.webdriver.common.keys import Keys\nfrom"
  },
  {
    "path": "dirigible/fts/tests/test_2529_HighlightErrorsInCells.py",
    "chars": 1187,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2531_DifficultStuffInCells.py",
    "chars": 4140,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2532_LambdasInCells.py",
    "chars": 750,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport re\nimport time\nfrom urlparse import urlparse\n"
  },
  {
    "path": "dirigible/fts/tests/test_2533_Numpy.py",
    "chars": 4715,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest, snapshot"
  },
  {
    "path": "dirigible/fts/tests/test_2534_JsonWorksheets.py",
    "chars": 6537,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import simplejson as json\nexcept ImportErro"
  },
  {
    "path": "dirigible/fts/tests/test_2535_RunWorksheetSerial.py",
    "chars": 3014,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\n\n\nclass T"
  },
  {
    "path": "dirigible/fts/tests/test_2536_ParallelFormulaExecution.py",
    "chars": 3538,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\nimport re\n\ntry:\n    impo"
  },
  {
    "path": "dirigible/fts/tests/test_2537_ErrorsInConsole.py",
    "chars": 3092,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nfrom functionaltest import FunctionalTest\n\nfrom textw"
  },
  {
    "path": "dirigible/fts/tests/test_2538_ShowStdoutInConsole.py",
    "chars": 2120,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\nfrom text"
  },
  {
    "path": "dirigible/fts/tests/test_2540_FrontPage.py",
    "chars": 2747,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest, Url\n\nfro"
  },
  {
    "path": "dirigible/fts/tests/test_2544_403_404_and_500_pages.py",
    "chars": 4475,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom urlparse import urljoin\n\nfrom functionaltest im"
  },
  {
    "path": "dirigible/fts/tests/test_2545_PageResizeBehaviour.py",
    "chars": 5008,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\r\n# All Rights Reserved\r\n#\r\n\r\n\r\nfrom functionaltest import FunctionalTest, sna"
  },
  {
    "path": "dirigible/fts/tests/test_2546_ListSheetsOnDashboard.py",
    "chars": 2389,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, SERVER_IP"
  },
  {
    "path": "dirigible/fts/tests/test_2547_EnterDataQuickly.py",
    "chars": 1415,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport time\n\nfrom functionaltest import FunctionalTe"
  },
  {
    "path": "dirigible/fts/tests/test_2548_UserCode.py",
    "chars": 2869,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2549_InterruptedRecalculations.py",
    "chars": 1648,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport time\nfrom textwrap import dedent\n\nfrom functi"
  },
  {
    "path": "dirigible/fts/tests/test_2550_EditableSheetName.py",
    "chars": 4018,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\nfrom text"
  },
  {
    "path": "dirigible/fts/tests/test_2554_SlicingInFormulae.py",
    "chars": 1094,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2556_BrokenUserCode.py",
    "chars": 3642,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, snapshot_"
  },
  {
    "path": "dirigible/fts/tests/test_2557_ClickAwaySavesUsercode.py",
    "chars": 998,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2558_MoreCellsByDefault.py",
    "chars": 1405,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\n\n\nclass T"
  },
  {
    "path": "dirigible/fts/tests/test_2559_FitEditorToCells.py",
    "chars": 1055,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\n\n\nclass T"
  },
  {
    "path": "dirigible/fts/tests/test_2562_ErrorInCellShouldBeClearedByConstants.py",
    "chars": 702,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass te"
  },
  {
    "path": "dirigible/fts/tests/test_2565_JSONAPIAuth.py",
    "chars": 16885,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\ntry:\n    impo"
  },
  {
    "path": "dirigible/fts/tests/test_2571_DocumentationAndBlogLinks.py",
    "chars": 1742,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\r\n# All Rights Reserved\r\n#\r\n\r\nfrom urlparse import urljoin\r\n\r\n\r\nfrom functiona"
  },
  {
    "path": "dirigible/fts/tests/test_2577_SaveColumnWidths.py",
    "chars": 3702,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\nimport time\n\nfrom functi"
  },
  {
    "path": "dirigible/fts/tests/test_2581_FormulaBar.py",
    "chars": 6151,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, snapshot_"
  },
  {
    "path": "dirigible/fts/tests/test_2582_ReferencingEmptyCell.py",
    "chars": 1087,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\n\n\nclass T"
  },
  {
    "path": "dirigible/fts/tests/test_2592_Cut_Copy_Paste_Within_Dirigible.py",
    "chars": 12982,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom textwrap"
  },
  {
    "path": "dirigible/fts/tests/test_2595_Spinner.py",
    "chars": 1149,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\r\n# All Rights Reserved\r\n#\r\n\r\n\r\nfrom functionaltest import FunctionalTest\r\n\r\n\r"
  },
  {
    "path": "dirigible/fts/tests/test_2597_CapRecalcTime.py",
    "chars": 1009,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n\nfrom functionaltest import FunctionalTest\n\n\nclass T"
  },
  {
    "path": "dirigible/fts/tests/test_2601_UndefinedShouldBeAvailableToUsercode.py",
    "chars": 773,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2602_SheetPageShouldDisplayBeforeFirstRecalcComplete.py",
    "chars": 1519,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2603_WorksheetsMayOnlyContainCells.py",
    "chars": 785,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nfrom textwrap import dedent\n\nfrom functionaltest impo"
  },
  {
    "path": "dirigible/fts/tests/test_2616_RootPageIsDashboard.py",
    "chars": 986,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom urlparse import urlparse, urlunparse\n\nfrom func"
  },
  {
    "path": "dirigible/fts/tests/test_2621_CanSaveSheetsWithLotsOfFormulae.py",
    "chars": 1822,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2622_CellRanges.py",
    "chars": 3498,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, Url\n\nfrom"
  },
  {
    "path": "dirigible/fts/tests/test_2631_BlogRedirect.py",
    "chars": 2124,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2633_CursorKeysMoveAroundGrid.py",
    "chars": 18540,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom function"
  },
  {
    "path": "dirigible/fts/tests/test_2635_SheetNameSelectedOnEdit.py",
    "chars": 897,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2639_SciPy_and_MpMath.py",
    "chars": 1319,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2642_RecalcTimesInConsole.py",
    "chars": 829,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2644_AdminOmniscience.py",
    "chars": 2651,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2650_UsercodeSandbox.py",
    "chars": 3445,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nfrom textwrap import dedent\n\ntry:\n    import unittest"
  },
  {
    "path": "dirigible/fts/tests/test_2651_SaveSheetNameOnBlur.py",
    "chars": 2056,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2652_CommitCellOnBlur.py",
    "chars": 2244,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2653_UsernameFocusedOnLoginPage.py",
    "chars": 92,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\n# Check added to T2525\n\n"
  },
  {
    "path": "dirigible/fts/tests/test_2654_CtrlSSavesUsercode.py",
    "chars": 1238,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom function"
  },
  {
    "path": "dirigible/fts/tests/test_2678_GlobalStateNotShared.py",
    "chars": 2053,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, snapshot_"
  },
  {
    "path": "dirigible/fts/tests/test_2682_CellAccessUsingA1.py",
    "chars": 852,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2685_ChangePassword.py",
    "chars": 5615,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nimport time\n\nfrom functionaltest import FunctionalTes"
  },
  {
    "path": "dirigible/fts/tests/test_2689_DontClearCellEditorWhenRecalcsHitClient.py",
    "chars": 2480,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\nfrom time import sleep\n\n"
  },
  {
    "path": "dirigible/fts/tests/test_2690_FocusShouldStartInGrid.py",
    "chars": 888,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\nimport key"
  },
  {
    "path": "dirigible/fts/tests/test_2691_AllowSettingValuesFromUsercodeBeforeLoadConstants.py",
    "chars": 848,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\ntry:\n    import unittes"
  },
  {
    "path": "dirigible/fts/tests/test_2701_NameResolutionWorks.py",
    "chars": 1020,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2702_HttpsInChrootJail.py",
    "chars": 845,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2704_OldStyleClassesInTheGrid.py",
    "chars": 1545,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport re\nfrom textwrap import dedent\n\nfrom function"
  },
  {
    "path": "dirigible/fts/tests/test_2711_ImportExcel.py",
    "chars": 6692,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, PAGE_LOAD"
  },
  {
    "path": "dirigible/fts/tests/test_2712_ImportCSV.py",
    "chars": 8903,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, PAGE_LOAD"
  },
  {
    "path": "dirigible/fts/tests/test_2726_FormulaBarTextSelection.py",
    "chars": 1105,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\nfrom key_"
  },
  {
    "path": "dirigible/fts/tests/test_2734_ClearCells.py",
    "chars": 6118,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\ntry:\n    import unittest2 as unittest\nexcept ImportE"
  },
  {
    "path": "dirigible/fts/tests/test_2735_CtrlKeysArePassedOnToBrowser.py",
    "chars": 958,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom function"
  },
  {
    "path": "dirigible/fts/tests/test_2741_Xlrd.py",
    "chars": 488,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2749_DisallowArbitraryKeysForWorksheet.py",
    "chars": 597,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2751_UsefulModules.py",
    "chars": 1077,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2758_LoadGridDataOnDemand.py",
    "chars": 1583,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom function"
  },
  {
    "path": "dirigible/fts/tests/test_2762_PythonConversion.py",
    "chars": 868,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2770_ClearDependentCellErrors.py",
    "chars": 1438,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2774_ExportCSV.py",
    "chars": 7349,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\nfrom os impor"
  },
  {
    "path": "dirigible/fts/tests/test_2781_FormulaAndFormattedValueMustBeStrings.py",
    "chars": 1220,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nfrom functionaltest imp"
  },
  {
    "path": "dirigible/fts/tests/test_2787_SignUp.py",
    "chars": 11370,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport re\nfrom urlparse import urlparse, urljoin\nimp"
  },
  {
    "path": "dirigible/fts/tests/test_2789_ErrorConsoleHTMLEscape.py",
    "chars": 607,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2795_Rewrite_Formulae_during_Cut_and_Paste.py",
    "chars": 17580,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2799_FillDownDuringPaste.py",
    "chars": 3152,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\nimport key"
  },
  {
    "path": "dirigible/fts/tests/test_2812_CutCopyPasteInEditMode.py",
    "chars": 1858,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom __future__ import with_statement\n\ntry:\n    impo"
  },
  {
    "path": "dirigible/fts/tests/test_2814_PublicWorksheets.py",
    "chars": 14464,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\nfrom __future__ import with_statement\n\nfrom os import"
  },
  {
    "path": "dirigible/fts/tests/test_2828_GridShouldNotStealFocusOnRecalc.py",
    "chars": 1279,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom textwrap import dedent\n\nimport key_codes\nfrom f"
  },
  {
    "path": "dirigible/fts/tests/test_2839_CutCopyPasteButtons.py",
    "chars": 1503,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\r\n# All Rights Reserved\r\n#\r\n\r\nfrom functionaltest import FunctionalTest\r\n\r\n\r\nc"
  },
  {
    "path": "dirigible/fts/tests/test_2844_CantMakeRowHeaderActive.py",
    "chars": 933,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\n\nclass Te"
  },
  {
    "path": "dirigible/fts/tests/test_2848_WorksheetBounds.py",
    "chars": 857,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\r\n# All Rights Reserved\r\n#\r\n\r\nfrom functionaltest import FunctionalTest\r\n\r\n\r\nc"
  },
  {
    "path": "dirigible/fts/tests/test_2862_CopyAndPasteFormulaWithErrors.py",
    "chars": 910,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport time\nfrom textwrap import dedent\n\nimport key_"
  },
  {
    "path": "dirigible/fts/tests/test_2872_CellTooltips.py",
    "chars": 1457,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nimport time\nfrom textwrap import dedent\n\nimport key_"
  },
  {
    "path": "dirigible/fts/tests/test_2873_IE_Warning.py",
    "chars": 1269,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest\n\nclass Tes"
  },
  {
    "path": "dirigible/fts/tests/test_2884_FeedbackForm.py",
    "chars": 11532,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd.\n# All Rights Reserved\n#\n\nfrom functionaltest import FunctionalTest, Url\n\n\ncla"
  },
  {
    "path": "dirigible/fts/tests/test_data/csv_file.csv",
    "chars": 31,
    "preview": "1,2,3\na,b,c\n£12.95,Sacrébleu!,\n"
  },
  {
    "path": "dirigible/fts/tests/test_data/excel_generated_csv.csv",
    "chars": 172,
    "preview": "some text,\"text with quotes \"\"'\"\"\"\"'\"\"\",\"text with a \ncarriage return\"\r\nsome european characters:,Herg,\r\nsome european m"
  },
  {
    "path": "dirigible/fts/tests/test_data/expected_csv_file.csv",
    "chars": 433,
    "preview": ",,,,\r\n,\"Data at A2, from a constant\",4,,\r\n,\"Data at A3, with a \\n that might need escaping\",,,\r\n,\"Data at A4, with 'sing"
  },
  {
    "path": "dirigible/fts/tests/test_data/expected_unicode_csv.csv",
    "chars": 8,
    "preview": "ゼロウィング\r\n"
  },
  {
    "path": "dirigible/fts/tests/test_data/japanese.csv",
    "chars": 11,
    "preview": "新世紀エヴァンゲリオン"
  },
  {
    "path": "dirigible/fts/tests/test_data/public_sheet_csv_file.csv",
    "chars": 16,
    "preview": ",\r\n,\r\n,23\r\n,25\r\n"
  },
  {
    "path": "dirigible/info_pages/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/info_pages/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/info_pages/models.py",
    "chars": 57,
    "preview": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "dirigible/info_pages/templates/non_logged_in_front_page.html",
    "chars": 2534,
    "preview": "{% extends \"base.html\" %}\n\n{% block title %}\n    Welcome to Dirigible, a programmable cloud spreadsheet\n{% endblock %}\n\n"
  },
  {
    "path": "dirigible/info_pages/templates/oss.html",
    "chars": 4467,
    "preview": "{% extends \"info_page.html\" %}\n\n{% block title %}\n    Thanks to Open Source Projects: Dirigible\n{% endblock %}\n\n{% block"
  },
  {
    "path": "dirigible/info_pages/templates/video.html",
    "chars": 633,
    "preview": "{% extends \"non_sheet_page_small_logo.html\" %}\n\n\n{% block title %}\n    The Video: Dirigible\n{% endblock %}\n\n\n{% block he"
  },
  {
    "path": "dirigible/info_pages/tests/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "dirigible/info_pages/tests/test_views.py",
    "chars": 2317,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\r\n# See LICENSE.md\r\n#\r\n\r\nfrom mock import patch, sentinel, "
  },
  {
    "path": "dirigible/info_pages/views.py",
    "chars": 601,
    "preview": "# Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n# See LICENSE.md\n#\n\nfrom django.shortcuts import render_to"
  },
  {
    "path": "dirigible/manage.py",
    "chars": 252,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
  },
  {
    "path": "dirigible/registration/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/registration/admin.py",
    "chars": 313,
    "preview": "from django.contrib import admin\n\nfrom registration.models import RegistrationProfile\n\n\nclass RegistrationAdmin(admin.Mo"
  },
  {
    "path": "dirigible/registration/forms.py",
    "chars": 5753,
    "preview": "\"\"\"\nForms and validation code for user registration.\n\n\"\"\"\n\n\nfrom django import forms\nfrom django.utils.translation impor"
  },
  {
    "path": "dirigible/registration/locale/ar/LC_MESSAGES/django.po",
    "chars": 2115,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/bg/LC_MESSAGES/django.po",
    "chars": 2215,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/de/LC_MESSAGES/django.po",
    "chars": 2317,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/el/LC_MESSAGES/django.po",
    "chars": 2289,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/en/LC_MESSAGES/django.po",
    "chars": 1628,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/es/LC_MESSAGES/django.po",
    "chars": 2325,
    "preview": "# Spanish translation for django-registration.\n# Copyright (C) 2007, James Bennet\n# This file is distributed under the s"
  },
  {
    "path": "dirigible/registration/locale/es_AR/LC_MESSAGES/django.po",
    "chars": 2251,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2008 Leonardo Manuel Rocha\n# This file is distributed under the same license a"
  },
  {
    "path": "dirigible/registration/locale/fr/LC_MESSAGES/django.po",
    "chars": 2271,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/he/LC_MESSAGES/django.po",
    "chars": 1997,
    "preview": "# translation of registration.\n# Copyright (C) 2008 THE registration'S COPYRIGHT HOLDER\n# This file is distributed under"
  },
  {
    "path": "dirigible/registration/locale/it/LC_MESSAGES/django.po",
    "chars": 2269,
    "preview": "# translation of django.po to Italiano\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed un"
  },
  {
    "path": "dirigible/registration/locale/ja/LC_MESSAGES/django.po",
    "chars": 1903,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/nl/LC_MESSAGES/django.po",
    "chars": 2279,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/pl/LC_MESSAGES/django.po",
    "chars": 2187,
    "preview": "# Polish translation for django-registration.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distrib"
  },
  {
    "path": "dirigible/registration/locale/pt_BR/LC_MESSAGES/django.po",
    "chars": 2199,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/ru/LC_MESSAGES/django.po",
    "chars": 2230,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/sr/LC_MESSAGES/django.po",
    "chars": 2337,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/sv/LC_MESSAGES/django.po",
    "chars": 2107,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/zh_CN/LC_MESSAGES/django.po",
    "chars": 1779,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/locale/zh_TW/LC_MESSAGES/django.po",
    "chars": 1779,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "dirigible/registration/management/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/registration/management/commands/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/registration/management/commands/cleanupregistration.py",
    "chars": 577,
    "preview": "\"\"\"\nA management command which deletes expired accounts (e.g.,\naccounts which signed up but never activated) from the da"
  },
  {
    "path": "dirigible/registration/migrations/0001_initial.py",
    "chars": 935,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nfrom django.co"
  },
  {
    "path": "dirigible/registration/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/registration/models.py",
    "chars": 10400,
    "preview": "import datetime\nimport random\nimport re\nimport sha\n\nfrom django.conf import settings\nfrom django.db import models\nfrom d"
  },
  {
    "path": "dirigible/registration/tests.py",
    "chars": 13397,
    "preview": "\"\"\"\nUnit tests for django-registration.\n\nThese tests assume that you've completed all the prerequisites for\ngetting djan"
  },
  {
    "path": "dirigible/registration/urls.py",
    "chars": 2620,
    "preview": "\"\"\"\nURLConf for Django user registration and authentication.\n\nIf the default behavior of the registration views is accep"
  },
  {
    "path": "dirigible/registration/views.py",
    "chars": 5770,
    "preview": "\"\"\"\nViews which allow users to create and activate accounts.\n\n\"\"\"\n\n\nfrom django.conf import settings\nfrom django.core.ur"
  },
  {
    "path": "dirigible/shared/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "dirigible/shared/models.py",
    "chars": 57,
    "preview": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "dirigible/shared/static/ace/ace-uncompressed.js",
    "chars": 427343,
    "preview": "/* ***** BEGIN LICENSE BLOCK *****\n * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n *\n * The contents of this file are subject to t"
  },
  {
    "path": "dirigible/shared/static/ace/ace.js",
    "chars": 158062,
    "preview": "(function(){if(window.require)require.packaged=!0;else{var a=function(b,c,d){typeof b!==\"string\"?a.original?a.original.a"
  },
  {
    "path": "dirigible/shared/static/ace/cockpit-uncompressed.js",
    "chars": 112794,
    "preview": "/* ***** BEGIN LICENSE BLOCK *****\n * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n *\n * The contents of this file are subject to t"
  },
  {
    "path": "dirigible/shared/static/ace/cockpit.js",
    "chars": 53015,
    "preview": "define(\"cockpit/index\",function(a,b,c){b.startup=function(b,c){a(\"pilot/index\"),a(\"cockpit/cli\").startup(b,c),a(\"cockpit"
  },
  {
    "path": "dirigible/shared/static/ace/mode-python.js",
    "chars": 3643,
    "preview": "define(\"ace/mode/python\",function(a,b,c){var d=a(\"pilot/oop\"),e=a(\"ace/mode/text\").Mode,f=a(\"ace/tokenizer\").Tokenizer,g"
  },
  {
    "path": "dirigible/shared/static/ace/worker-javascript.js",
    "chars": 118294,
    "preview": "function initSender(){var a=require(\"pilot/event_emitter\").EventEmitter,b=require(\"pilot/oop\"),c=function(){};(function("
  },
  {
    "path": "dirigible/shared/static/dirigible/examples/pricelist-json-api-demo.html",
    "chars": 5833,
    "preview": "<html>\r\n    <head>\r\n        <title>Dirigible pricelist</title>\r\n        <script\r\n            type=\"text/javascript\"\r\n   "
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/cell_editor.js",
    "chars": 3598,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\r\n// See LICENSE.md\r\n//\r\n\r\n\r\neditor_methods = {\r\n\r\n    ini"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/console_view.js",
    "chars": 551,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n(function($) {\n    $.extend(true, w"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/dialogs.js",
    "chars": 1968,
    "preview": "(function($) {\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"Dialogs\": {\n                \"Initialise\""
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/editor_commands.js",
    "chars": 876,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n\n(function($) {\n    // register nam"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/feedback_dialog.js",
    "chars": 2602,
    "preview": "(function($) {\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"FeedbackDialog\": {\n                \"Init"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/grid_commands.js",
    "chars": 3910,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n\n(function($) {\n    // register nam"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/grid_content_converter.js",
    "chars": 716,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\nfunction getGridCellFormula(grid, s"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/grid_interaction_handler.js",
    "chars": 5645,
    "preview": "(function($) {\n    // register namespace\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"GridInteractio"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/grid_remote_model.js",
    "chars": 5713,
    "preview": "(function($) {\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"GridRemoteModel\": GridRemoteModel\n      "
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/grid_view.js",
    "chars": 6402,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n(function($) {\n    $.extend(true, w"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/htmlescape.js",
    "chars": 449,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\nfunction htmlescape(untrusted_strin"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/keyboard_cellrange_selector.js",
    "chars": 2205,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\nvar TAB = 9;\nvar SHIFT = 16;\n\n\n(fun"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/page_commands.js",
    "chars": 598,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n\n(function($) {\n    // register nam"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/page_interaction_handler.js",
    "chars": 3807,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n(function($) {\n    // register names"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/page_view.js",
    "chars": 964,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n(function($) {\n    $.extend(true, w"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/security_settings.js",
    "chars": 5881,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n(function($) {\n    $.extend(true, w"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/selection_model.js",
    "chars": 3075,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\r\n// See LICENSE.md\r\n//\r\n\r\n(function($) {\r\n    // register"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/sheet_page_utils.js",
    "chars": 1422,
    "preview": "(function($) {\n    // register namespace\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"SheetUtils\": {"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/toolbar_interaction_handler.js",
    "chars": 582,
    "preview": "(function($) {\n    // register namespace\n    $.extend(true, window, {\n        \"Dirigible\": {\n            \"ToolbarInterac"
  },
  {
    "path": "dirigible/shared/static/dirigible/scripts/usercode_view.js",
    "chars": 1016,
    "preview": "// Copyright (c) 2010 Resolver Systems Ltd, PythonAnywhere LLP\n// See LICENSE.md\n//\n\n(function($) {\n    $.extend(true, w"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/base.css",
    "chars": 1888,
    "preview": "html {\n    height: 100%;\n}\n\n\nbody {\n    height: 100%;\n    margin: 0;\n    padding: 0;\n    font-family: Helvetica, Arial, "
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/coming_soon_page.css",
    "chars": 151,
    "preview": "#id_coming_soon {\n    margin-top: 35px;\n    margin-bottom: 35px;\n    font-size: 28px;\n    color: #4B576D;\n    text-align"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/contact.css",
    "chars": 256,
    "preview": "p.address {\r\n    margin-left: 2ex;\r\n}\r\n\r\n\r\np.regulatory {\r\n    clear: both; \r\n    padding-top: 20px; \r\n    font-size: sm"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/error.css",
    "chars": 300,
    "preview": "#id_error_wrap {\r\n    width: 29em;\r\n    clear: both;\r\n    margin-top: 4em;\r\n    margin-left: auto;\r\n    margin-right: au"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/index.css",
    "chars": 1050,
    "preview": ".id_dirigible_tagline {\n    font-size: 20px;\n    color: #4B576D;\n    text-align: center;\n}\n\n#id_grey_stripe_hwrap {\n    "
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/info_page.css",
    "chars": 999,
    "preview": "#id_extra_banner_spacing {\n    clear: both; \n    margin-bottom: 10px;\n}\n\nh1 {\n    padding-top: 0px;\n    margin-top: 0px;"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/login.css",
    "chars": 1288,
    "preview": "#id_login_form_wrap {\n    width: 29em;\n    clear: both;\n    margin-top: 4em;\n    margin-left: auto;\n    margin-right: au"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/non_sheet_page.css",
    "chars": 1281,
    "preview": ".centered-block {\r\n    width: 710px;\r\n    clear: both;\r\n    margin-left: auto;\r\n    margin-right: auto;\r\n}\r\n#id_ie_warni"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/pricing.css",
    "chars": 656,
    "preview": "#id_beta_free_splash {\r\n    background-color: #FFEB8C;\r\n}\r\n\r\n\r\n#id_price_plan_table {\r\n    border-spacing: 20px;\r\n}\r\n\r\n#"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/registration.css",
    "chars": 1322,
    "preview": "#id_signup_vwrap {\r\n    margin-top: 3em;\r\n}\r\n\r\n\r\n#id_signup_hwrap {\r\n    width: 30em;\r\n    clear: both;\r\n    margin-left"
  },
  {
    "path": "dirigible/shared/static/dirigible/styles/sheet_page.css",
    "chars": 5176,
    "preview": "body {\n    /* prevents splitter resizing that sometimes leaves space for\n       scrollbars that are not there. This does"
  }
]

// ... and 203 more files (download for full content)

About this extraction

This page contains the full source code of the pythonanywhere/dirigible-spreadsheet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 403 files (3.2 MB), approximately 855.6k tokens, and a symbol index with 1979 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!