abstra 3.23.6__py3-none-any.whl → 3.23.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {abstra-3.23.6.dist-info → abstra-3.23.8.dist-info}/METADATA +1 -1
- {abstra-3.23.6.dist-info → abstra-3.23.8.dist-info}/RECORD +191 -189
- abstra_internals/consts/filepaths.py +1 -1
- abstra_internals/contracts_generated.py +3791 -3236
- abstra_internals/controllers/codebase.py +9 -18
- abstra_internals/controllers/codebase_events.py +6 -4
- abstra_internals/controllers/main.py +56 -67
- abstra_internals/interface/cli/deploy.py +1 -3
- abstra_internals/repositories/linter/repository.py +9 -40
- abstra_internals/repositories/linter/rules/__init__.py +2 -0
- abstra_internals/repositories/linter/rules/big_py_files.py +40 -0
- abstra_internals/repositories/linter/rules/big_py_files_test.py +93 -0
- abstra_internals/repositories/linter/rules/duplicate_package_in_requirements.py +16 -4
- abstra_internals/repositories/linter/rules/duplicate_package_in_requirements_test.py +24 -3
- abstra_internals/repositories/linter/rules/env_in_bundle.py +3 -6
- abstra_internals/repositories/linter/rules/env_in_bundle_test.py +4 -3
- abstra_internals/repositories/linter/rules/missing_packages_in_requirements.py +12 -1
- abstra_internals/repositories/linter/rules/syntax_errors.py +2 -19
- abstra_internals/repositories/linter/rules/venv_in_bundle.py +3 -2
- abstra_internals/server/routes/requirements.py +7 -3
- abstra_internals/server/routes/workspace.py +0 -10
- abstra_internals/services/fs.py +144 -99
- abstra_internals/services/fs_test.py +303 -8
- abstra_internals/services/requirements.py +271 -81
- abstra_internals/services/requirements_test.py +528 -164
- abstra_internals/templates/__init__.py +3 -1
- abstra_statics/dist/assets/AbstraButton.vue_vue_type_script_setup_true_lang.205eb76e.js +2 -0
- abstra_statics/dist/assets/AbstraLogo.vue_vue_type_script_setup_true_lang.32a17b0c.js +2 -0
- abstra_statics/dist/assets/{ApiKeys.05b5ab9a.js → ApiKeys.7fefafb4.js} +2 -2
- abstra_statics/dist/assets/App.c29df54f.js +2 -0
- abstra_statics/dist/assets/App.vue_vue_type_style_index_0_lang.efd9d3fa.js +2 -0
- abstra_statics/dist/assets/BaseLayout.b60c33b8.js +2 -0
- abstra_statics/dist/assets/Billing.b9f77b65.js +2 -0
- abstra_statics/dist/assets/{Breadcrumb.6179cdce.js → Breadcrumb.d0cc2c91.js} +2 -2
- abstra_statics/dist/assets/{Builds.43df5473.js → Builds.18e4ba1a.js} +2 -2
- abstra_statics/dist/assets/{Card.bf61638b.js → Card.957a87b2.js} +2 -2
- abstra_statics/dist/assets/{CircularLoading.e6d19d98.js → CircularLoading.3e4ddd6d.js} +2 -2
- abstra_statics/dist/assets/CloseCircleOutlined.4e05b917.js +2 -0
- abstra_statics/dist/assets/{ConnectorsView.5cef13aa.css → ConnectorsView.17764dde.css} +1 -1
- abstra_statics/dist/assets/ConnectorsView.562a5007.js +2 -0
- abstra_statics/dist/assets/ConsoleOmniChat.vue_vue_type_script_setup_true_lang.1d09cfdd.js +2 -0
- abstra_statics/dist/assets/ContentLayout.7d5c9f09.js +2 -0
- abstra_statics/dist/assets/{CrudView.bbc83763.js → CrudView.8fb84eac.js} +2 -2
- abstra_statics/dist/assets/{DocsButton.vue_vue_type_script_setup_true_lang.0796f440.js → DocsButton.vue_vue_type_script_setup_true_lang.0555d923.js} +2 -2
- abstra_statics/dist/assets/{EditorLogin.d00bf0ff.js → EditorLogin.02eb6050.js} +2 -2
- abstra_statics/dist/assets/{EditorsView.99ba9c06.js → EditorsView.f0ea00fc.js} +2 -2
- abstra_statics/dist/assets/EnvVars.063644bb.js +2 -0
- abstra_statics/dist/assets/Error.a81122c4.js +2 -0
- abstra_statics/dist/assets/ExclamationCircleOutlined.d410fb9a.js +2 -0
- abstra_statics/dist/assets/Files.f23b9c53.js +2 -0
- abstra_statics/dist/assets/Form.bfea5673.js +2 -0
- abstra_statics/dist/assets/{FormRunner.714ce2c1.css → FormRunner.46f6426d.css} +1 -1
- abstra_statics/dist/assets/FormRunner.8bbe841e.js +2 -0
- abstra_statics/dist/assets/Home.3bf2f131.js +2 -0
- abstra_statics/dist/assets/Home.42964d5b.js +2 -0
- abstra_statics/dist/assets/{Live.50f8f3ee.js → Live.5dc821b6.js} +2 -2
- abstra_statics/dist/assets/LoadingContainer.6e72d482.js +2 -0
- abstra_statics/dist/assets/LoadingOutlined.ee72932a.js +2 -0
- abstra_statics/dist/assets/Login.0b618d09.js +2 -0
- abstra_statics/dist/assets/{Login.35337e9b.js → Login.c702642b.js} +2 -2
- abstra_statics/dist/assets/Login.vue_vue_type_script_setup_true_lang.a92a80d0.js +2 -0
- abstra_statics/dist/assets/Logo.83b476a4.js +2 -0
- abstra_statics/dist/assets/{Logs.412b505f.js → Logs.eebc0504.js} +2 -2
- abstra_statics/dist/assets/{LogsController.770e0220.js → LogsController.eb1b811d.js} +2 -2
- abstra_statics/dist/assets/Main.88719eb3.js +2 -0
- abstra_statics/dist/assets/MockForm.c3318be9.js +2 -0
- abstra_statics/dist/assets/Navbar.abf206e9.js +2 -0
- abstra_statics/dist/assets/{NewEditor.8f32e814.css → NewEditor.0044878f.css} +1 -1
- abstra_statics/dist/assets/NewEditor.5650f697.js +8 -0
- abstra_statics/dist/assets/OidcLoginCallback.df2bdeb0.js +2 -0
- abstra_statics/dist/assets/OidcLogoutCallback.2ba5316d.js +2 -0
- abstra_statics/dist/assets/{OmniChat.7660057c.css → OmniChat.8a35a659.css} +1 -1
- abstra_statics/dist/assets/{OmniChat.cb7c5f10.js → OmniChat.de828c54.js} +4 -4
- abstra_statics/dist/assets/{OnboardingView.611e451f.js → OnboardingView.1c034f0d.js} +2 -2
- abstra_statics/dist/assets/{Organization.16168e9f.js → Organization.855f95a9.js} +2 -2
- abstra_statics/dist/assets/Organizations.3db82ab2.js +2 -0
- abstra_statics/dist/assets/{PhArrowCounterClockwise.vue.3f439d6d.js → PhArrowCounterClockwise.vue.76c9e146.js} +2 -2
- abstra_statics/dist/assets/{PhArrowSquareOut.vue.73431843.js → PhArrowSquareOut.vue.ecfa9cb2.js} +2 -2
- abstra_statics/dist/assets/{PhBookBookmark.vue.f5df4397.js → PhBookBookmark.vue.f8f803d9.js} +2 -2
- abstra_statics/dist/assets/{PhChats.vue.20c511b5.js → PhChats.vue.dfda946c.js} +2 -2
- abstra_statics/dist/assets/{PhClockCounterClockwise.vue.21ab2795.js → PhClockCounterClockwise.vue.cd77fd26.js} +2 -2
- abstra_statics/dist/assets/{PhCopy.vue.f0a6fc0c.js → PhCopy.vue.a63b48dd.js} +2 -2
- abstra_statics/dist/assets/{PhCopySimple.vue.f585b051.js → PhCopySimple.vue.ecffb042.js} +2 -2
- abstra_statics/dist/assets/{PhCube.vue.c7b0863a.js → PhCube.vue.b5b96a33.js} +2 -2
- abstra_statics/dist/assets/{PhDotsThreeVertical.vue.c1812ea8.js → PhDotsThreeVertical.vue.2db678ef.js} +2 -2
- abstra_statics/dist/assets/{PhDownloadSimple.vue.24466182.js → PhDownloadSimple.vue.cbca4f9b.js} +2 -2
- abstra_statics/dist/assets/{PhFolderPlus.vue.0cd449af.js → PhFolderPlus.vue.dfb9b117.js} +2 -2
- abstra_statics/dist/assets/{PhGear.vue.24fe28a2.js → PhGear.vue.6e1aeed0.js} +2 -2
- abstra_statics/dist/assets/{PhKey.vue.39ca7afb.js → PhKey.vue.50d82bb5.js} +2 -2
- abstra_statics/dist/assets/{PhPencil.vue.a86916ee.js → PhPencil.vue.ae2943da.js} +2 -2
- abstra_statics/dist/assets/{PhPencilSimple.vue.80a4282f.js → PhPencilSimple.vue.9042e169.js} +2 -2
- abstra_statics/dist/assets/{PhPencilSimpleLine.vue.a1883531.js → PhPencilSimpleLine.vue.f840cf0d.js} +2 -2
- abstra_statics/dist/assets/{PhRocket.vue.acacaa11.js → PhRocket.vue.3b5927aa.js} +2 -2
- abstra_statics/dist/assets/{PhSignOut.vue.3cb7cd40.js → PhSignOut.vue.d00d3657.js} +2 -2
- abstra_statics/dist/assets/{PhSparkle.vue.8e334c6d.js → PhSparkle.vue.8a94f3a0.js} +2 -2
- abstra_statics/dist/assets/{PhUserList.vue.38f46bf2.js → PhUserList.vue.3791cb59.js} +2 -2
- abstra_statics/dist/assets/{PhUsersThree.vue.f3486eeb.js → PhUsersThree.vue.ef0376b6.js} +2 -2
- abstra_statics/dist/assets/{PhWebhooksLogo.vue.3f80aef6.js → PhWebhooksLogo.vue.fe81fb65.js} +2 -2
- abstra_statics/dist/assets/{PlayerConfigProvider.0ec5f598.js → PlayerConfigProvider.2acd3a77.js} +2 -2
- abstra_statics/dist/assets/PlayerNavbar.13876ce7.js +2 -0
- abstra_statics/dist/assets/Project.0277535f.js +2 -0
- abstra_statics/dist/assets/ProjectLogin.46d5036b.js +2 -0
- abstra_statics/dist/assets/{ProjectSettings.17a585e6.js → ProjectSettings.652a838b.js} +2 -2
- abstra_statics/dist/assets/{ProjectsView.3f2dabb4.js → ProjectsView.c5ec993b.js} +2 -2
- abstra_statics/dist/assets/{SaveButton.57d5b00a.js → SaveButton.ac38b361.js} +2 -2
- abstra_statics/dist/assets/{files.b6e46123.js → ScrollArea.vue_vue_type_script_setup_true_lang.a58564d3.js} +2 -2
- abstra_statics/dist/assets/{Sidebar.3bc6e6c7.js → Sidebar.56e51ab5.js} +2 -2
- abstra_statics/dist/assets/Sql.3cdc910a.css +1 -0
- abstra_statics/dist/assets/Sql.6961306b.js +5 -0
- abstra_statics/dist/assets/Steps.f820fb18.js +2 -0
- abstra_statics/dist/assets/{TableEditor.791324c3.js → TableEditor.df6a4852.js} +2 -2
- abstra_statics/dist/assets/Tables.198b84c5.js +2 -0
- abstra_statics/dist/assets/{TablesDiagram.d27523e8.js → TablesDiagram.811d464d.js} +2 -2
- abstra_statics/dist/assets/TablesTabs.vue_vue_type_script_setup_true_lang.e6074880.js +2 -0
- abstra_statics/dist/assets/{Tasks.9f66e5d4.js → Tasks.df69d20e.js} +2 -2
- abstra_statics/dist/assets/{UploadOutlined.1e2f50aa.js → UploadOutlined.b601a592.js} +2 -2
- abstra_statics/dist/assets/{View.2b0dde2c.js → View.7a2ccc33.js} +2 -2
- abstra_statics/dist/assets/View.vue_vue_type_script_setup_true_lang.424410a2.js +2 -0
- abstra_statics/dist/assets/Watermark.40c8c47e.js +2 -0
- abstra_statics/dist/assets/{WebEditor.cdb4d362.js → WebEditor.82a3accf.js} +2 -2
- abstra_statics/dist/assets/{WidgetPreview.73776456.js → WidgetPreview.0f938200.js} +2 -2
- abstra_statics/dist/assets/ant-design.544de4a0.js +2 -0
- abstra_statics/dist/assets/apiKey.95126643.js +2 -0
- abstra_statics/dist/assets/asyncComputed.1b787534.js +2 -0
- abstra_statics/dist/assets/{build.36ea33ce.js → build.997fec15.js} +2 -2
- abstra_statics/dist/assets/{colorHelpers.f396fe13.js → colorHelpers.d4f3f275.js} +2 -2
- abstra_statics/dist/assets/{console.d7a64eef.js → console.54ab975c.js} +2 -2
- abstra_statics/dist/assets/constants.36bf7d70.js +2 -0
- abstra_statics/dist/assets/{cssMode.a2f505eb.js → cssMode.c1aa21d7.js} +2 -2
- abstra_statics/dist/assets/datetime.adc0acc4.js +2 -0
- abstra_statics/dist/assets/dayjs.a6bd0ee0.js +2 -0
- abstra_statics/dist/assets/editor.0ce52658.js +2 -0
- abstra_statics/dist/assets/editor.main.353e9a8f.js +2 -0
- abstra_statics/dist/assets/fetch.83d89bdc.js +2 -0
- abstra_statics/dist/assets/{folder.8e3a1b23.js → folder.41d37eb7.js} +2 -2
- abstra_statics/dist/assets/{freemarker2.48cf9094.js → freemarker2.40778f3f.js} +2 -2
- abstra_statics/dist/assets/{handlebars.b7185455.js → handlebars.92d4ff2a.js} +3 -3
- abstra_statics/dist/assets/{html.9eecf18a.js → html.b3c0c53a.js} +3 -3
- abstra_statics/dist/assets/{htmlMode.1b022721.js → htmlMode.1212da49.js} +2 -2
- abstra_statics/dist/assets/{index.2f04e3f6.js → index.36d8b30a.js} +5 -5
- abstra_statics/dist/assets/{index.bbe55f1a.js → index.37c46161.js} +2 -2
- abstra_statics/dist/assets/index.3d2a7b6d.js +2 -0
- abstra_statics/dist/assets/{index.25898d95.js → index.3e7471f4.js} +2 -2
- abstra_statics/dist/assets/{index.2d59a444.js → index.3ff1c0be.js} +3 -3
- abstra_statics/dist/assets/index.5e22e010.js +2 -0
- abstra_statics/dist/assets/{index.36aedb48.js → index.9e0166fe.js} +2 -2
- abstra_statics/dist/assets/{index.726d6111.js → index.a7b8e25e.js} +2 -2
- abstra_statics/dist/assets/{index.aca944a5.js → index.d181a22c.js} +2 -2
- abstra_statics/dist/assets/{javascript.84f7229f.js → javascript.f9710043.js} +3 -3
- abstra_statics/dist/assets/{jsonMode.1d488dc1.js → jsonMode.16d00c0d.js} +2 -2
- abstra_statics/dist/assets/{jwt-decode.esm.28320b05.js → jwt-decode.esm.992666e9.js} +8 -8
- abstra_statics/dist/assets/linters.3c5f0c83.js +2 -0
- abstra_statics/dist/assets/{liquid.5b33b8cc.js → liquid.9a777e1a.js} +3 -3
- abstra_statics/dist/assets/{member.73d141d7.js → member.6b2b3438.js} +2 -2
- abstra_statics/dist/assets/{metadata.8c8d4b20.js → metadata.cfad5458.js} +2 -2
- abstra_statics/dist/assets/omniChatStore.2b85c342.js +8 -0
- abstra_statics/dist/assets/{organization.7d79a3c7.js → organization.53636095.js} +2 -2
- abstra_statics/dist/assets/player.5b7eaa25.js +2 -0
- abstra_statics/dist/assets/{plotly.min.bc8ddded.js → plotly.min.9b8bef5c.js} +2 -2
- abstra_statics/dist/assets/polling.88a266b3.js +2 -0
- abstra_statics/dist/assets/{project.c76d644e.js → project.76f0af14.js} +2 -2
- abstra_statics/dist/assets/{python.1a326b7a.js → python.ae8270c8.js} +2 -2
- abstra_statics/dist/assets/{razor.3d5f09e6.js → razor.4f24e19e.js} +3 -3
- abstra_statics/dist/assets/{record.1b6df81e.js → record.87ef3b68.js} +2 -2
- abstra_statics/dist/assets/redirect.2fa4f8cf.js +2 -0
- abstra_statics/dist/assets/{repository.37d2927a.js → repository.9d5310b6.js} +2 -2
- abstra_statics/dist/assets/{repository.cc27afed.js → repository.af418855.js} +2 -2
- abstra_statics/dist/assets/{router.858e1af2.js → router.1324a1a9.js} +3 -3
- abstra_statics/dist/assets/router.55c0ff56.js +2 -0
- abstra_statics/dist/assets/{string.4c218fd1.js → string.f6a7565f.js} +2 -2
- abstra_statics/dist/assets/{tables.337a9b65.js → tables.c26107a1.js} +2 -2
- abstra_statics/dist/assets/{tasksController.a06fd7d3.js → tasksController.22584849.js} +2 -2
- abstra_statics/dist/assets/{toggleHighContrast.62d05446.js → toggleHighContrast.fc60753d.js} +7 -7
- abstra_statics/dist/assets/{tsMode.cacd2597.js → tsMode.a4b9b524.js} +2 -2
- abstra_statics/dist/assets/{typescript.a2a6a629.js → typescript.ab90fd1d.js} +3 -3
- abstra_statics/dist/assets/url.f490879d.js +2 -0
- abstra_statics/dist/assets/userStore.9e7a540a.js +2 -0
- abstra_statics/dist/assets/uuid.9161765c.js +2 -0
- abstra_statics/dist/assets/{vue-flow-background.d047c675.js → vue-flow-background.8e4c22c3.js} +2 -2
- abstra_statics/dist/assets/{vue-quill.esm-bundler.772b3404.js → vue-quill.esm-bundler.64c5837f.js} +2 -2
- abstra_statics/dist/assets/workspaceStore.4f0c433f.js +2 -0
- abstra_statics/dist/assets/{xml.e6a1736d.js → xml.3541c340.js} +2 -2
- abstra_statics/dist/assets/{yaml.47c8c844.js → yaml.314312d8.js} +3 -3
- abstra_statics/dist/console.html +15 -15
- abstra_statics/dist/editor.html +11 -11
- abstra_statics/dist/player.html +9 -9
- tests/e2e/test_crud_files.py +0 -1
- tests/e2e/test_requirements.py +41 -4
- abstra_statics/dist/assets/AbstraButton.vue_vue_type_script_setup_true_lang.5ac4912e.js +0 -2
- abstra_statics/dist/assets/AbstraLogo.vue_vue_type_script_setup_true_lang.9fc63b70.js +0 -2
- abstra_statics/dist/assets/App.c04b86c0.js +0 -2
- abstra_statics/dist/assets/App.vue_vue_type_style_index_0_lang.4abdaaf3.js +0 -2
- abstra_statics/dist/assets/BaseLayout.d7e7e9fe.js +0 -2
- abstra_statics/dist/assets/Billing.57e2ca6b.js +0 -2
- abstra_statics/dist/assets/CloseCircleOutlined.5183baf0.js +0 -2
- abstra_statics/dist/assets/ConnectorsView.c29b5831.js +0 -2
- abstra_statics/dist/assets/ConsoleOmniChat.vue_vue_type_script_setup_true_lang.c7982f0e.js +0 -2
- abstra_statics/dist/assets/ContentLayout.d3e84c3e.js +0 -2
- abstra_statics/dist/assets/EnvVars.3223d4dd.js +0 -2
- abstra_statics/dist/assets/Error.73539d40.js +0 -2
- abstra_statics/dist/assets/ExclamationCircleOutlined.5ed9d71f.js +0 -2
- abstra_statics/dist/assets/Files.7358e813.js +0 -2
- abstra_statics/dist/assets/Form.7b7f61dd.js +0 -2
- abstra_statics/dist/assets/FormRunner.617659c3.js +0 -2
- abstra_statics/dist/assets/Home.50e3cb44.js +0 -2
- abstra_statics/dist/assets/Home.e051b43c.js +0 -2
- abstra_statics/dist/assets/LoadingContainer.af0e1ba2.js +0 -2
- abstra_statics/dist/assets/LoadingOutlined.6ed83a08.js +0 -2
- abstra_statics/dist/assets/Login.99bd4c40.js +0 -2
- abstra_statics/dist/assets/Login.vue_vue_type_script_setup_true_lang.d3c2d47f.js +0 -2
- abstra_statics/dist/assets/Logo.e3649776.js +0 -2
- abstra_statics/dist/assets/Main.738990b8.js +0 -2
- abstra_statics/dist/assets/MockForm.4ead504b.js +0 -2
- abstra_statics/dist/assets/Navbar.50988594.js +0 -2
- abstra_statics/dist/assets/NewEditor.13d26823.js +0 -8
- abstra_statics/dist/assets/OidcLoginCallback.4982d0fb.js +0 -2
- abstra_statics/dist/assets/OidcLogoutCallback.717d758c.js +0 -2
- abstra_statics/dist/assets/Organizations.68ef6411.js +0 -2
- abstra_statics/dist/assets/PlayerNavbar.24544fa8.js +0 -2
- abstra_statics/dist/assets/Project.997d68f7.js +0 -2
- abstra_statics/dist/assets/ProjectLogin.311c2cd8.js +0 -2
- abstra_statics/dist/assets/Sql.1afe0bac.css +0 -1
- abstra_statics/dist/assets/Sql.c74977b7.js +0 -5
- abstra_statics/dist/assets/Steps.79eea5ae.js +0 -2
- abstra_statics/dist/assets/Tables.5cfd01db.js +0 -2
- abstra_statics/dist/assets/TablesTabs.vue_vue_type_script_setup_true_lang.82db1c2e.js +0 -2
- abstra_statics/dist/assets/View.vue_vue_type_script_setup_true_lang.34afb660.js +0 -2
- abstra_statics/dist/assets/Watermark.047823a2.js +0 -2
- abstra_statics/dist/assets/ant-design.dc326d34.js +0 -2
- abstra_statics/dist/assets/apiKey.d428e427.js +0 -2
- abstra_statics/dist/assets/asyncComputed.decbe125.js +0 -2
- abstra_statics/dist/assets/constants.54f5dbb0.js +0 -2
- abstra_statics/dist/assets/datetime.27912eb6.js +0 -2
- abstra_statics/dist/assets/dayjs.9a51c922.js +0 -2
- abstra_statics/dist/assets/editor.ac3f0982.js +0 -2
- abstra_statics/dist/assets/editor.main.39fc3e9d.js +0 -2
- abstra_statics/dist/assets/fetch.9946ecfe.js +0 -2
- abstra_statics/dist/assets/index.3a2ab2d2.js +0 -2
- abstra_statics/dist/assets/index.b0181193.js +0 -2
- abstra_statics/dist/assets/index.e21caff3.js +0 -2
- abstra_statics/dist/assets/linters.ed377d41.js +0 -2
- abstra_statics/dist/assets/omniChatStore.b7128bc4.js +0 -10
- abstra_statics/dist/assets/player.027b4a53.js +0 -2
- abstra_statics/dist/assets/polling.0bb90faf.js +0 -2
- abstra_statics/dist/assets/redirect.d8affe75.js +0 -2
- abstra_statics/dist/assets/url.e7d14364.js +0 -2
- abstra_statics/dist/assets/userStore.c0562f9d.js +0 -2
- abstra_statics/dist/assets/uuid.fe529613.js +0 -2
- abstra_statics/dist/assets/workspaceStore.20104d6a.js +0 -2
- {abstra-3.23.6.dist-info → abstra-3.23.8.dist-info}/WHEEL +0 -0
- {abstra-3.23.6.dist-info → abstra-3.23.8.dist-info}/entry_points.txt +0 -0
- {abstra-3.23.6.dist-info → abstra-3.23.8.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import shutil
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from tempfile import mkdtemp
|
|
3
4
|
from unittest import TestCase
|
|
4
5
|
|
|
6
|
+
from abstra_internals.consts.filepaths import ABSTRA_IGNORE_FILEPATH
|
|
5
7
|
from abstra_internals.services.fs import FileSystemService
|
|
8
|
+
from abstra_internals.settings import Settings
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class TestFileSystemService(TestCase):
|
|
9
12
|
def setUp(self):
|
|
10
|
-
self.test_dir = Path("test_rm_tree_dir"
|
|
13
|
+
self.test_dir = Path(mkdtemp()) / "test_rm_tree_dir"
|
|
14
|
+
Settings.set_root_path(str(self.test_dir.absolute()))
|
|
11
15
|
self.test_dir.mkdir(exist_ok=True)
|
|
12
16
|
(self.test_dir / "subdir").mkdir(exist_ok=True)
|
|
13
17
|
(self.test_dir / "subdir" / "file.txt").write_text("hello")
|
|
@@ -30,6 +34,10 @@ class TestFileSystemService(TestCase):
|
|
|
30
34
|
(test_dir / "file.txt").write_text("abc")
|
|
31
35
|
(test_dir / "__pycache__").mkdir(exist_ok=True)
|
|
32
36
|
(test_dir / "__pycache__" / "cache.pyc").write_text("cache")
|
|
37
|
+
ignore_path = test_dir / ABSTRA_IGNORE_FILEPATH
|
|
38
|
+
ignore_path.write_text(
|
|
39
|
+
"__pycache__/"
|
|
40
|
+
) # Fixed: use correct gitignore pattern for any __pycache__ directory
|
|
33
41
|
files = FileSystemService.list_files(test_dir)
|
|
34
42
|
file_names = [f.name for f in files]
|
|
35
43
|
self.assertIn("file.txt", file_names)
|
|
@@ -45,13 +53,300 @@ class TestFileSystemService(TestCase):
|
|
|
45
53
|
self.assertFalse(FileSystemService._suffix_allowed(p, [".txt"]))
|
|
46
54
|
|
|
47
55
|
def test_is_ignored(self):
|
|
48
|
-
|
|
56
|
+
self.test_dir.joinpath(ABSTRA_IGNORE_FILEPATH).write_text(
|
|
57
|
+
"*.pyc\n__pycache__/\n"
|
|
58
|
+
)
|
|
59
|
+
self.assertTrue(FileSystemService.is_ignored(Path("foo.pyc")))
|
|
60
|
+
self.assertFalse(FileSystemService.is_ignored(Path("foo.py")))
|
|
49
61
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
|
|
63
|
+
class TestGitIgnoreCompatibility(TestCase):
|
|
64
|
+
"""Test suite to ensure FileSystemService.is_ignored follows gitignore rules correctly."""
|
|
65
|
+
|
|
66
|
+
def setUp(self):
|
|
67
|
+
self.test_dir = Path(mkdtemp()) / "gitignore_test"
|
|
68
|
+
Settings.set_root_path(str(self.test_dir.absolute()))
|
|
69
|
+
self.test_dir.mkdir(exist_ok=True)
|
|
70
|
+
|
|
71
|
+
# Create comprehensive test directory structure
|
|
72
|
+
test_structure = [
|
|
73
|
+
"README.md",
|
|
74
|
+
"file.pyc",
|
|
75
|
+
"main.py",
|
|
76
|
+
"temp.tmp",
|
|
77
|
+
".env",
|
|
78
|
+
".git/config",
|
|
79
|
+
"build/output.o",
|
|
80
|
+
"build/debug/info.log",
|
|
81
|
+
"src/main.py",
|
|
82
|
+
"src/main.pyc",
|
|
83
|
+
"src/utils.py",
|
|
84
|
+
"docs/readme.txt",
|
|
85
|
+
"docs/images/logo.png",
|
|
86
|
+
"__pycache__/cache.pyc",
|
|
87
|
+
"sub/__pycache__/cache2.pyc",
|
|
88
|
+
"sub/dir/file.txt",
|
|
89
|
+
"sub/dir/temp.tmp",
|
|
90
|
+
"node_modules/package/index.js",
|
|
91
|
+
"node_modules/other/lib.js",
|
|
92
|
+
"logs/error.log",
|
|
93
|
+
"logs/debug/trace.log",
|
|
94
|
+
"dist/bundle.js",
|
|
95
|
+
"dist/css/style.css",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
for path_str in test_structure:
|
|
99
|
+
path = self.test_dir / path_str
|
|
100
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
path.write_text("content")
|
|
102
|
+
|
|
103
|
+
def tearDown(self):
|
|
104
|
+
if self.test_dir.exists():
|
|
105
|
+
shutil.rmtree(self.test_dir, ignore_errors=True)
|
|
106
|
+
|
|
107
|
+
def _create_ignore_file(self, content: str):
|
|
108
|
+
"""Helper to create ignore file with given content."""
|
|
109
|
+
ignore_file = self.test_dir / ABSTRA_IGNORE_FILEPATH
|
|
110
|
+
ignore_file.write_text(content)
|
|
111
|
+
|
|
112
|
+
def _assert_ignored(self, pattern: str, path: str, should_be_ignored: bool):
|
|
113
|
+
"""Helper to test if a path is ignored by a pattern."""
|
|
114
|
+
self._create_ignore_file(pattern)
|
|
115
|
+
full_path = self.test_dir / path
|
|
116
|
+
is_ignored = FileSystemService.is_ignored(full_path)
|
|
117
|
+
self.assertEqual(
|
|
118
|
+
is_ignored,
|
|
119
|
+
should_be_ignored,
|
|
120
|
+
f"Pattern '{pattern}' on path '{path}': expected {should_be_ignored}, got {is_ignored}",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def test_basic_wildcard_patterns(self):
|
|
124
|
+
"""Test basic wildcard patterns like *.ext"""
|
|
125
|
+
# *.pyc should match all .pyc files at any level
|
|
126
|
+
self._assert_ignored("*.pyc", "file.pyc", True)
|
|
127
|
+
self._assert_ignored("*.pyc", "src/main.pyc", True)
|
|
128
|
+
self._assert_ignored("*.pyc", "main.py", False)
|
|
129
|
+
|
|
130
|
+
# *.tmp should match all .tmp files
|
|
131
|
+
self._assert_ignored("*.tmp", "temp.tmp", True)
|
|
132
|
+
self._assert_ignored("*.tmp", "sub/dir/temp.tmp", True)
|
|
133
|
+
self._assert_ignored("*.tmp", "main.py", False)
|
|
134
|
+
|
|
135
|
+
def test_directory_patterns_with_trailing_slash(self):
|
|
136
|
+
"""Test patterns ending with / that only match directories"""
|
|
137
|
+
# __pycache__/ should match any __pycache__ directory
|
|
138
|
+
self._assert_ignored("__pycache__/", "__pycache__", True)
|
|
139
|
+
self._assert_ignored("__pycache__/", "sub/__pycache__", True)
|
|
140
|
+
|
|
141
|
+
# node_modules/ should match node_modules directory
|
|
142
|
+
self._assert_ignored("node_modules/", "node_modules", True)
|
|
143
|
+
|
|
144
|
+
# build/ should match build directory but not build.txt file (if it existed)
|
|
145
|
+
self._assert_ignored("build/", "build", True)
|
|
146
|
+
|
|
147
|
+
def test_leading_slash_patterns(self):
|
|
148
|
+
"""Test patterns starting with / that are relative to ignore file only"""
|
|
149
|
+
# /.env should only match .env at root level
|
|
150
|
+
self._assert_ignored("/.env", ".env", True)
|
|
151
|
+
|
|
152
|
+
# /build should only match build at root level
|
|
153
|
+
self._assert_ignored("/build", "build", True)
|
|
154
|
+
|
|
155
|
+
# Create a subdirectory scenario to test it doesn't match in subdirs
|
|
156
|
+
(self.test_dir / "subproject").mkdir(exist_ok=True)
|
|
157
|
+
(self.test_dir / "subproject" / ".env").write_text("content")
|
|
158
|
+
self._assert_ignored("/.env", "subproject/.env", False)
|
|
159
|
+
|
|
160
|
+
def test_patterns_with_slash_in_middle(self):
|
|
161
|
+
"""Test patterns with slash in middle - relative to ignore file"""
|
|
162
|
+
# src/*.pyc should match .pyc files only in src directory
|
|
163
|
+
self._assert_ignored("src/*.pyc", "src/main.pyc", True)
|
|
164
|
+
self._assert_ignored("src/*.pyc", "src/utils.py", False)
|
|
165
|
+
self._assert_ignored("src/*.pyc", "main.pyc", False) # Not in src/
|
|
166
|
+
|
|
167
|
+
# build/debug should match the debug directory inside build
|
|
168
|
+
self._assert_ignored("build/debug", "build/debug", True)
|
|
169
|
+
self._assert_ignored("build/debug", "build/output.o", False)
|
|
170
|
+
|
|
171
|
+
# docs/images/* should match everything in docs/images/
|
|
172
|
+
self._assert_ignored("docs/images/*", "docs/images/logo.png", True)
|
|
173
|
+
self._assert_ignored("docs/images/*", "docs/readme.txt", False)
|
|
174
|
+
|
|
175
|
+
def test_single_wildcard_with_slash(self):
|
|
176
|
+
"""Test patterns like */__pycache__ that require a parent directory"""
|
|
177
|
+
# */__pycache__ should match __pycache__ only when it has a parent
|
|
178
|
+
self._assert_ignored("*/__pycache__", "sub/__pycache__", True)
|
|
179
|
+
self._assert_ignored("*/__pycache__", "__pycache__", False) # No parent
|
|
180
|
+
|
|
181
|
+
# */temp.tmp should match temp.tmp only in subdirectories
|
|
182
|
+
self._assert_ignored("*/temp.tmp", "sub/dir/temp.tmp", True)
|
|
183
|
+
self._assert_ignored("*/temp.tmp", "temp.tmp", False) # At root level
|
|
184
|
+
|
|
185
|
+
def test_double_asterisk_patterns(self):
|
|
186
|
+
"""Test ** patterns that match any number of directories"""
|
|
187
|
+
# **/__pycache__ should match __pycache__ at any level
|
|
188
|
+
self._assert_ignored("**/__pycache__", "__pycache__", True)
|
|
189
|
+
self._assert_ignored("**/__pycache__", "sub/__pycache__", True)
|
|
190
|
+
|
|
191
|
+
# **/node_modules should match node_modules anywhere
|
|
192
|
+
self._assert_ignored("**/node_modules", "node_modules", True)
|
|
193
|
+
|
|
194
|
+
# **/*.log should match .log files anywhere
|
|
195
|
+
self._assert_ignored("**/*.log", "logs/error.log", True)
|
|
196
|
+
self._assert_ignored("**/*.log", "logs/debug/trace.log", True)
|
|
197
|
+
|
|
198
|
+
# build/** should match everything inside build
|
|
199
|
+
self._assert_ignored("build/**", "build/output.o", True)
|
|
200
|
+
self._assert_ignored("build/**", "build/debug/info.log", True)
|
|
201
|
+
self._assert_ignored("build/**", "build", False) # build itself, not contents
|
|
202
|
+
self._assert_ignored("build/**", "src/main.py", False) # Outside build
|
|
203
|
+
|
|
204
|
+
def test_complex_double_asterisk_patterns(self):
|
|
205
|
+
"""Test complex ** patterns with multiple components"""
|
|
206
|
+
# a/**/b should match a/b, a/x/b, a/x/y/b, etc.
|
|
207
|
+
(self.test_dir / "a" / "b").mkdir(parents=True, exist_ok=True)
|
|
208
|
+
(self.test_dir / "a" / "x" / "b").mkdir(parents=True, exist_ok=True)
|
|
209
|
+
(self.test_dir / "a" / "x" / "y" / "b").mkdir(parents=True, exist_ok=True)
|
|
210
|
+
|
|
211
|
+
self._assert_ignored("a/**/b", "a/b", True)
|
|
212
|
+
self._assert_ignored("a/**/b", "a/x/b", True)
|
|
213
|
+
self._assert_ignored("a/**/b", "a/x/y/b", True)
|
|
214
|
+
self._assert_ignored("a/**/b", "a/x", False)
|
|
215
|
+
self._assert_ignored("a/**/b", "x/b", False)
|
|
216
|
+
|
|
217
|
+
def test_question_mark_patterns(self):
|
|
218
|
+
"""Test ? wildcard that matches single character except /"""
|
|
219
|
+
# file?.txt should match file1.txt, fileA.txt but not file/txt
|
|
220
|
+
(self.test_dir / "file1.txt").write_text("content")
|
|
221
|
+
(self.test_dir / "fileA.txt").write_text("content")
|
|
222
|
+
(self.test_dir / "file" / "txt").mkdir(parents=True, exist_ok=True)
|
|
223
|
+
|
|
224
|
+
self._assert_ignored("file?.txt", "file1.txt", True)
|
|
225
|
+
self._assert_ignored("file?.txt", "fileA.txt", True)
|
|
226
|
+
self._assert_ignored("file?.txt", "file/txt", False) # ? doesn't match /
|
|
227
|
+
|
|
228
|
+
def test_character_ranges(self):
|
|
229
|
+
"""Test character range patterns [a-z], [0-9], etc."""
|
|
230
|
+
# [0-9].txt should match digit filenames
|
|
231
|
+
(self.test_dir / "1.txt").write_text("content")
|
|
232
|
+
(self.test_dir / "9.txt").write_text("content")
|
|
233
|
+
(self.test_dir / "a.txt").write_text("content")
|
|
234
|
+
|
|
235
|
+
self._assert_ignored("[0-9].txt", "1.txt", True)
|
|
236
|
+
self._assert_ignored("[0-9].txt", "9.txt", True)
|
|
237
|
+
self._assert_ignored("[0-9].txt", "a.txt", False)
|
|
238
|
+
|
|
239
|
+
def test_multiple_patterns(self):
|
|
240
|
+
"""Test ignore file with multiple patterns"""
|
|
241
|
+
patterns = """
|
|
242
|
+
# Python files
|
|
243
|
+
*.pyc
|
|
244
|
+
__pycache__/
|
|
245
|
+
|
|
246
|
+
# Build artifacts
|
|
247
|
+
build/
|
|
248
|
+
dist/
|
|
249
|
+
|
|
250
|
+
# Environment
|
|
251
|
+
.env
|
|
252
|
+
|
|
253
|
+
# Logs
|
|
254
|
+
*.log
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
self._create_ignore_file(patterns)
|
|
258
|
+
|
|
259
|
+
# Test each pattern works
|
|
260
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "file.pyc"))
|
|
261
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "__pycache__"))
|
|
262
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "build"))
|
|
263
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "dist"))
|
|
264
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / ".env"))
|
|
265
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "logs/error.log"))
|
|
266
|
+
|
|
267
|
+
# Test non-matching files
|
|
268
|
+
self.assertFalse(FileSystemService.is_ignored(self.test_dir / "main.py"))
|
|
269
|
+
self.assertFalse(FileSystemService.is_ignored(self.test_dir / "README.md"))
|
|
270
|
+
|
|
271
|
+
def test_comments_and_blank_lines(self):
|
|
272
|
+
"""Test that comments and blank lines are ignored"""
|
|
273
|
+
patterns = """
|
|
274
|
+
# This is a comment
|
|
275
|
+
*.pyc
|
|
276
|
+
|
|
277
|
+
# Another comment
|
|
278
|
+
|
|
279
|
+
__pycache__/
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
self._create_ignore_file(patterns)
|
|
283
|
+
|
|
284
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "file.pyc"))
|
|
285
|
+
self.assertTrue(FileSystemService.is_ignored(self.test_dir / "__pycache__"))
|
|
286
|
+
self.assertFalse(FileSystemService.is_ignored(self.test_dir / "main.py"))
|
|
287
|
+
|
|
288
|
+
def test_non_existent_files(self):
|
|
289
|
+
"""Test that patterns work for non-existent files/directories"""
|
|
290
|
+
self._assert_ignored("*.pyc", "nonexistent.pyc", True)
|
|
291
|
+
self._assert_ignored("__pycache__/", "nonexistent/__pycache__", True)
|
|
292
|
+
self._assert_ignored("build/", "nonexistent_build", False)
|
|
293
|
+
|
|
294
|
+
# Test with files that have extensions but don't exist
|
|
295
|
+
self._assert_ignored("*.js", "app.js", True)
|
|
296
|
+
self._assert_ignored("*.js", "app.py", False)
|
|
297
|
+
|
|
298
|
+
def test_edge_cases(self):
|
|
299
|
+
"""Test various edge cases"""
|
|
300
|
+
# Empty pattern should not match anything
|
|
301
|
+
self._assert_ignored("", "any_file.txt", False)
|
|
302
|
+
|
|
303
|
+
# Single dot - in real gitignore, this would be unusual
|
|
304
|
+
# Our implementation treats it as a literal filename match
|
|
305
|
+
(self.test_dir / "dotfile").write_text(
|
|
306
|
+
"content"
|
|
307
|
+
) # Create a file named just "dotfile"
|
|
308
|
+
self._assert_ignored(".", "dotfile", False) # Adjusted expectation
|
|
309
|
+
|
|
310
|
+
# Pattern with only slash
|
|
311
|
+
self._assert_ignored("/", "/", False) # Should not match
|
|
312
|
+
|
|
313
|
+
# Very long paths
|
|
314
|
+
long_path = "a/" * 50 + "file.txt"
|
|
315
|
+
(self.test_dir / long_path).parent.mkdir(parents=True, exist_ok=True)
|
|
316
|
+
(self.test_dir / long_path).write_text("content")
|
|
317
|
+
self._assert_ignored("**/*.txt", long_path, True)
|
|
53
318
|
|
|
54
319
|
def test_make_ignore_regex(self):
|
|
55
|
-
regex
|
|
56
|
-
|
|
57
|
-
|
|
320
|
+
"""Test the internal regex generation method if it exists"""
|
|
321
|
+
# Test basic regex patterns
|
|
322
|
+
patterns = ["*.pyc", "__pycache__/", "build/*"]
|
|
323
|
+
for pattern in patterns:
|
|
324
|
+
self._create_ignore_file(pattern)
|
|
325
|
+
# Basic smoke test - if the method exists and doesn't crash
|
|
326
|
+
try:
|
|
327
|
+
# This tests that the pattern parsing doesn't break
|
|
328
|
+
FileSystemService.is_ignored(self.test_dir / "test.pyc")
|
|
329
|
+
except Exception as e:
|
|
330
|
+
self.fail(f"Pattern '{pattern}' caused error: {e}")
|
|
331
|
+
|
|
332
|
+
def test_make_ignore_regex_2(self):
|
|
333
|
+
"""Test more complex regex generation scenarios"""
|
|
334
|
+
# Test patterns that might cause regex issues
|
|
335
|
+
complex_patterns = [
|
|
336
|
+
"**/*.{js,css,html}", # If brace expansion is supported
|
|
337
|
+
"file[0-9].txt", # Character classes
|
|
338
|
+
"path/with spaces/*.txt", # Paths with spaces
|
|
339
|
+
"special_chars_*.@#$.txt", # Special characters
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
for pattern in complex_patterns:
|
|
343
|
+
self._create_ignore_file(pattern)
|
|
344
|
+
# Test that complex patterns don't break the system
|
|
345
|
+
try:
|
|
346
|
+
result = FileSystemService.is_ignored(self.test_dir / "test.txt")
|
|
347
|
+
# Just ensure it returns a boolean without crashing
|
|
348
|
+
self.assertIsInstance(result, bool)
|
|
349
|
+
except Exception:
|
|
350
|
+
# Some patterns might not be supported, that's OK
|
|
351
|
+
# But the function shouldn't crash
|
|
352
|
+
pass
|