From 168294602364f3fc7f2f2939442b05dac7607fdb Mon Sep 17 00:00:00 2001 From: Jason Thomas Date: Fri, 7 Feb 2025 08:24:03 -0700 Subject: [PATCH] Upgrade python packages using poetry --- .env | 2 +- .github/workflows/api_tests.yml | 10 +- .github/workflows/python_unit_tests.yml | 10 +- docs.openc3.com/docs/development/testing.md | 8 +- .../js/import-map-overrides-5.1.0.min.js.map | 1 - openc3-ruby/Dockerfile-ubi | 2 +- openc3.code-workspace | 6 + openc3/Dockerfile | 3 +- openc3/python/.gitignore | 2 +- openc3/python/README.md | 9 +- openc3/python/poetry.lock | 1145 +++++++++++++++++ openc3/python/pyproject.toml | 87 +- openc3/python/requirements-dev.txt | 31 - openc3/python/requirements.txt | 15 - openc3/python/test/api/test_interface_api.py | 8 +- openc3/python/test/api/test_router_api.py | 2 +- scripts/release/package_audit.rb | 22 +- scripts/release/package_audit_lib.rb | 41 +- 18 files changed, 1251 insertions(+), 153 deletions(-) delete mode 100644 openc3-cosmos-init/plugins/packages/openc3-tool-base/public/js/import-map-overrides-5.1.0.min.js.map create mode 100644 openc3/python/poetry.lock delete mode 100644 openc3/python/requirements-dev.txt delete mode 100644 openc3/python/requirements.txt diff --git a/.env b/.env index a25665a271..467a9997cb 100644 --- a/.env +++ b/.env @@ -12,7 +12,7 @@ OPENC3_ENTERPRISE_REGISTRY=ghcr.io OPENC3_ENTERPRISE_NAMESPACE=openc3 OPENC3_UBI_REGISTRY=registry1.dso.mil OPENC3_UBI_IMAGE=ironbank/redhat/ubi/ubi8-minimal -OPENC3_UBI_TAG=8.8 +OPENC3_UBI_TAG=8.10 # Defined here as blank to avoid warnings. Used in the compose.yaml to pass '-ubi'. OPENC3_IMAGE_SUFFIX= # Bucket & Volume configuration diff --git a/.github/workflows/api_tests.yml b/.github/workflows/api_tests.yml index eea5da5c75..90a70bc448 100644 --- a/.github/workflows/api_tests.yml +++ b/.github/workflows/api_tests.yml @@ -107,17 +107,17 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements.txt - pip install -r requirements-dev.txt + pip install poetry + poetry install working-directory: openc3/python - name: Lint with ruff run: | - ruff --config=../openc3/python/pyproject.toml --format=github scripts/*.py + poetry run ruff --config=../openc3/python/pyproject.toml --output-format=github scripts/*.py working-directory: openc3-cosmos-script-runner-api - name: Run unit tests run: | - coverage run -m pytest ./test/ - coverage xml -i + poetry run coverage run -m pytest ./test/ + poetry run coverage xml -i working-directory: openc3-cosmos-script-runner-api - uses: codecov/codecov-action@v5 with: diff --git a/.github/workflows/python_unit_tests.yml b/.github/workflows/python_unit_tests.yml index 6fcec69024..677d0d4552 100644 --- a/.github/workflows/python_unit_tests.yml +++ b/.github/workflows/python_unit_tests.yml @@ -35,17 +35,17 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements.txt - pip install -r requirements-dev.txt + pip install poetry + poetry install working-directory: openc3/python - name: Lint with ruff run: | - ruff --format=github openc3 + poetry run ruff check --output-format=github openc3 working-directory: openc3/python - name: Run unit tests run: | - coverage run -m pytest ./test/ - coverage xml -i + poetry run coverage run -m pytest ./test/ + poetry run coverage xml -i working-directory: openc3/python - uses: codecov/codecov-action@v5 with: diff --git a/docs.openc3.com/docs/development/testing.md b/docs.openc3.com/docs/development/testing.md index 1d9a9e3934..ba4a9e07fe 100644 --- a/docs.openc3.com/docs/development/testing.md +++ b/docs.openc3.com/docs/development/testing.md @@ -75,10 +75,10 @@ Code coverage reports can be found at `cosmos/openc3/coverage/index.html` 1. Navigate to **cosmos/openc3/python** folder. Run the command: ```bash - cosmos/openc3/python % python -m pip install -r requirements-dev.txt - cosmos/openc3/python % python -m pip install -r requirements.txt - cosmos/openc3/python % coverage run -m pytest - cosmos/openc3/python % coverage html + cosmos/openc3/python % python -m pip install poetry + cosmos/openc3/python % poetry install + cosmos/openc3/python % poetry run coverage run -m pytest + cosmos/openc3/python % poetry run coverage html ``` Code coverage reports can be found at `cosmos/openc3/python/coverage/index.html` diff --git a/openc3-cosmos-init/plugins/packages/openc3-tool-base/public/js/import-map-overrides-5.1.0.min.js.map b/openc3-cosmos-init/plugins/packages/openc3-tool-base/public/js/import-map-overrides-5.1.0.min.js.map deleted file mode 100644 index 0eb551d8fb..0000000000 --- a/openc3-cosmos-init/plugins/packages/openc3-tool-base/public/js/import-map-overrides-5.1.0.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"import-map-overrides.js","sources":["../src/util/string-regex.js","../src/util/includes.js","../src/api/js-api.js","../src/util/url-parameter.js","../node_modules/.pnpm/preact@10.24.0/node_modules/preact/dist/preact.mjs","../src/ui/list/module-dialog.component.js","../src/ui/list/external-importmap-dialog.component.js","../src/ui/dev-lib-overrides.component.js","../src/ui/list/list.component.js","../src/ui/popup.component.js","../src/ui/full-ui.component.js","../src/ui/custom-elements.js"],"sourcesContent":["// from https://github.com/sindresorhus/escape-string-regexp\nexport const escapeStringRegexp = (string) => {\n if (typeof string !== \"string\") {\n throw new TypeError(\"Expected a string\");\n }\n\n // Escape characters with special meaning either inside or outside character sets.\n // Use a simple backslash escape when it’s always valid, and a `\\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.\n return string.replace(/[|\\\\{}()[\\]^$+*?.]/g, \"\\\\$&\").replace(/-/g, \"\\\\x2d\");\n};\n","export function includes(obj, item) {\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n if (obj[i] === item) {\n return true;\n }\n }\n return false;\n } else if (typeof obj === \"string\") {\n return obj.indexOf(item) >= 0;\n } else {\n throw Error(`Can't call includes on ${typeof obj}`);\n }\n}\n","import { escapeStringRegexp } from \"../util/string-regex\";\nimport { includes } from \"../util/includes.js\";\nimport { getParameterByName } from \"../util/url-parameter\";\n\nconst localStoragePrefix = \"import-map-override:\";\nconst disabledOverridesLocalStorageKey = \"import-map-overrides-disabled\";\nconst externalOverridesLocalStorageKey = \"import-map-overrides-external-maps\";\nconst overrideAttribute = \"data-is-importmap-override\";\nconst domainsMeta = \"import-map-overrides-domains\";\nconst allowListPrefix = \"allowlist:\";\nconst denyListPrefix = \"denylist:\";\nexport const queryParamOverridesName = \"imo\";\n\nconst importMapMetaElement = document.querySelector(\n 'meta[name=\"importmap-type\"]',\n);\n\nconst domainsElement = document.querySelector(`meta[name=\"${domainsMeta}\"]`);\n\nconst externalOverrideMapPromises = {};\n\nexport const importMapType =\n importMapMetaElement?.getAttribute(\"content\") ?? \"importmap\";\n\nexport let isDisabled;\n\nif (domainsElement) {\n const content = domainsElement.getAttribute(\"content\");\n if (!content) {\n console.warn(`Invalid ${domainsMeta} meta element - content required.`);\n }\n\n const matchHostname = (domain) =>\n new RegExp(escapeStringRegexp(domain).replace(\"\\\\*\", \".+\")).test(\n window.location.hostname,\n );\n\n if (content.indexOf(allowListPrefix) === 0) {\n const allowedDomains = content.slice(allowListPrefix.length).split(\",\");\n isDisabled = !allowedDomains.some(matchHostname);\n } else if (content.indexOf(denyListPrefix) === 0) {\n const deniedDomains = content.slice(denyListPrefix.length).split(\",\");\n isDisabled = deniedDomains.some(matchHostname);\n } else {\n // eslint-disable-next-line no-console\n console.log(\n `Invalid ${domainsMeta} meta content attribute - must start with ${allowListPrefix} or ${denyListPrefix}`,\n );\n }\n} else {\n isDisabled = false;\n}\n\nif (!canAccessLocalStorage()) {\n console.warn(\n \"Disabling import-map-overrides, since local storage is not readable\",\n );\n isDisabled = true;\n}\n\nif (!isDisabled) {\n init();\n}\n\nfunction init() {\n const serverOverrides = importMapMetaElement\n ? importMapMetaElement.hasAttribute(\"server-cookie\")\n : false;\n const serverOnly = importMapMetaElement\n ? importMapMetaElement.hasAttribute(\"server-only\")\n : false;\n const allowQueryParamOverride = importMapMetaElement\n ? importMapMetaElement.hasAttribute(\"allow-query-param-override\")\n : false;\n\n let defaultMapPromise;\n\n window.importMapOverrides = {\n addOverride(moduleName, url) {\n const portRegex = /^\\d+$/g;\n if (portRegex.test(url)) {\n url = imo.getUrlFromPort(moduleName, url);\n }\n const key = localStoragePrefix + moduleName;\n localStorage.setItem(key, url);\n if (serverOverrides) {\n document.cookie = `${key}=${url}`;\n }\n fireChangedEvent();\n return imo.getOverrideMap();\n },\n getOverrideMap(includeDisabled = false) {\n const overrides = createEmptyImportMap();\n const disabledOverrides = imo.getDisabledOverrides();\n\n const setOverride = (moduleName, path) => {\n if (includeDisabled || !(disabledOverrides.indexOf(moduleName) >= 0)) {\n overrides.imports[moduleName] = path;\n }\n };\n\n // get from localstorage\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key.indexOf(localStoragePrefix) === 0) {\n setOverride(\n key.slice(localStoragePrefix.length),\n localStorage.getItem(key),\n );\n }\n }\n\n // get from url if query param exist\n if (allowQueryParamOverride) {\n const queryParam = getParameterByName(\n queryParamOverridesName,\n window.location != window.parent.location\n ? document.referrer\n : window.location.href,\n );\n\n if (queryParam) {\n let queryParamImportMap;\n try {\n queryParamImportMap = JSON.parse(queryParam);\n } catch (e) {\n throw Error(\n `Invalid importMap query param - text content must be json`,\n );\n }\n Object.keys(queryParamImportMap.imports).forEach((moduleName) => {\n setOverride(moduleName, queryParamImportMap.imports[moduleName]);\n });\n }\n }\n\n return overrides;\n },\n removeOverride(moduleName) {\n const key = localStoragePrefix + moduleName;\n const hasItem = localStorage.getItem(key) !== null;\n localStorage.removeItem(key);\n if (serverOverrides) {\n document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;\n }\n imo.enableOverride(moduleName);\n fireChangedEvent();\n return hasItem;\n },\n async getOverrideScopes() {\n const scopes = {};\n const defaultMap = await imo.getDefaultMap();\n const overrideMap = imo.getOverrideMap();\n for (let moduleName in overrideMap.imports) {\n const defaultUrl = defaultMap.imports[moduleName];\n if (defaultUrl) {\n const defaultResolution = new URL(defaultUrl, window.location.href)\n .href;\n const overrideUrl = new URL(\n overrideMap.imports[moduleName],\n window.location.href,\n ).href;\n const overrideBase =\n overrideUrl.slice(0, overrideUrl.lastIndexOf(\"/\")) + \"/\";\n for (let scope in defaultMap.scopes || {}) {\n if (defaultResolution.startsWith(scope)) {\n scopes[overrideBase] = {\n ...(scopes[overrideBase] || {}),\n ...defaultMap.scopes[scope],\n };\n }\n }\n }\n }\n\n return { scopes };\n },\n resetOverrides() {\n Object.keys(imo.getOverrideMap(true).imports).forEach((moduleName) => {\n imo.removeOverride(moduleName);\n });\n localStorage.removeItem(disabledOverridesLocalStorageKey);\n localStorage.removeItem(externalOverridesLocalStorageKey);\n fireChangedEvent();\n return imo.getOverrideMap();\n },\n hasOverrides() {\n return Object.keys(imo.getOverrideMap().imports).length > 0;\n },\n getUrlFromPort(moduleName, port) {\n const fileName = moduleName.replace(/@/g, \"\").replace(/\\//g, \"-\");\n return `//localhost:${port}/${fileName}.js`;\n },\n enableUI() {\n const customElementName = \"import-map-overrides-full\";\n const showWhenLocalStorage = \"show-when-local-storage\";\n let customElement = document.querySelector(customElementName);\n\n if (!customElement) {\n customElement = document.createElement(customElementName);\n customElement.setAttribute(showWhenLocalStorage, \"true\");\n document.body.appendChild(customElement);\n }\n\n const localStorageKey = customElement.getAttribute(showWhenLocalStorage);\n if (localStorageKey) {\n localStorage.setItem(localStorageKey, true);\n customElement.renderWithPreact();\n }\n },\n mergeImportMap(originalMap, newMap) {\n const outMap = createEmptyImportMap();\n for (let i in originalMap.imports) {\n outMap.imports[i] = originalMap.imports[i];\n }\n for (let i in newMap.imports) {\n outMap.imports[i] = newMap.imports[i];\n }\n for (let i in originalMap.scopes) {\n outMap.scopes[i] = originalMap.scopes[i];\n }\n for (let i in newMap.scopes) {\n outMap.scopes[i] = newMap.scopes[i];\n }\n return outMap;\n },\n resetDefaultMap() {\n defaultMapPromise = null;\n },\n getDefaultMap() {\n return (\n defaultMapPromise ||\n (defaultMapPromise = Array.prototype.reduce.call(\n document.querySelectorAll(\n `script[type=\"${importMapType}\"], script[type=\"overridable-importmap\"]`,\n ),\n (promise, scriptEl) => {\n if (scriptEl.hasAttribute(overrideAttribute)) {\n return promise;\n } else {\n let nextPromise;\n if (scriptEl.src) {\n nextPromise = fetchExternalMap(scriptEl.src);\n } else {\n nextPromise = Promise.resolve(JSON.parse(scriptEl.textContent));\n }\n\n return Promise.all([promise, nextPromise]).then(\n ([originalMap, newMap]) =>\n imo.mergeImportMap(originalMap, newMap),\n );\n }\n },\n Promise.resolve(createEmptyImportMap()),\n ))\n );\n },\n getCurrentPageMap() {\n return Promise.all([\n imo.getDefaultMap(),\n imo.getExternalOverrideMap(imo.getCurrentPageExternalOverrides()),\n ]).then(([defaultMap, externalOverridesMap]) => {\n return imo.mergeImportMap(\n imo.mergeImportMap(defaultMap, externalOverridesMap),\n initialOverrideMap,\n );\n });\n },\n getCurrentPageExternalOverrides() {\n const currentPageExternalOverrides = [];\n document\n .querySelectorAll(\n `[${overrideAttribute}]:not([id=\"import-map-overrides\"])`,\n )\n .forEach((externalOverrideEl) => {\n currentPageExternalOverrides.push(externalOverrideEl.src);\n });\n return currentPageExternalOverrides;\n },\n getNextPageMap() {\n return Promise.all([\n imo.getDefaultMap(),\n imo.getExternalOverrideMap(),\n ]).then(([defaultMap, externalOverridesMap]) => {\n return imo.mergeImportMap(\n imo.mergeImportMap(defaultMap, externalOverridesMap),\n imo.getOverrideMap(),\n );\n });\n },\n disableOverride(moduleName) {\n const disabledOverrides = imo.getDisabledOverrides();\n if (!includes(disabledOverrides, moduleName)) {\n localStorage.setItem(\n disabledOverridesLocalStorageKey,\n JSON.stringify(disabledOverrides.concat(moduleName)),\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n enableOverride(moduleName) {\n const disabledOverrides = imo.getDisabledOverrides();\n const index = disabledOverrides.indexOf(moduleName);\n if (index >= 0) {\n disabledOverrides.splice(index, 1);\n localStorage.setItem(\n disabledOverridesLocalStorageKey,\n JSON.stringify(disabledOverrides),\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n getDisabledOverrides() {\n const disabledOverrides = localStorage.getItem(\n disabledOverridesLocalStorageKey,\n );\n return disabledOverrides ? JSON.parse(disabledOverrides) : [];\n },\n isDisabled(moduleName) {\n return includes(imo.getDisabledOverrides(), moduleName);\n },\n getExternalOverrides() {\n let localStorageValue = localStorage.getItem(\n externalOverridesLocalStorageKey,\n );\n return localStorageValue ? JSON.parse(localStorageValue).sort() : [];\n },\n addExternalOverride(url) {\n url = new URL(url, document.baseURI).href;\n const overrides = imo.getExternalOverrides();\n if (includes(overrides, url)) {\n return false;\n } else {\n localStorage.setItem(\n externalOverridesLocalStorageKey,\n JSON.stringify(overrides.concat(url)),\n );\n fireChangedEvent();\n return true;\n }\n },\n removeExternalOverride(url) {\n const overrides = imo.getExternalOverrides();\n if (includes(overrides, url)) {\n localStorage.setItem(\n externalOverridesLocalStorageKey,\n JSON.stringify(overrides.filter((override) => override !== url)),\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n getExternalOverrideMap(externalOverrides = imo.getExternalOverrides()) {\n return externalOverrides.reduce((result, externalOverride) => {\n const fetchPromise =\n externalOverrideMapPromises[externalOverride] ||\n (externalOverrideMapPromises[externalOverride] =\n fetchExternalMap(externalOverride));\n return Promise.all([result, fetchPromise]).then(\n ([firstMap, secondMap]) => {\n return imo.mergeImportMap(firstMap, secondMap);\n },\n );\n }, Promise.resolve(createEmptyImportMap()));\n },\n isExternalMapValid(importMapUrl) {\n const promise =\n externalOverrideMapPromises[importMapUrl] ||\n (externalOverrideMapPromises[importMapUrl] =\n fetchExternalMap(importMapUrl));\n return promise.then(\n () => !includes(imo.invalidExternalMaps, importMapUrl),\n );\n },\n invalidExternalMaps: [],\n };\n\n const imo = window.importMapOverrides;\n\n let canFireCustomEvents = true;\n try {\n if (CustomEvent) {\n new CustomEvent(\"a\");\n } else {\n canFireCustomEvents = false;\n }\n } catch (err) {\n canFireCustomEvents = false;\n }\n\n function fireChangedEvent() {\n fireEvent(\"change\");\n }\n\n function fireEvent(type) {\n // Set timeout so that event fires after the change has totally finished\n setTimeout(() => {\n const eventType = `import-map-overrides:${type}`;\n const event = canFireCustomEvents\n ? new CustomEvent(eventType)\n : document.createEvent(\"CustomEvent\");\n if (!canFireCustomEvents) {\n event.initCustomEvent(eventType, true, true, null);\n }\n window.dispatchEvent(event);\n });\n }\n\n const initialOverrideMap = imo.getOverrideMap();\n const initialExternalOverrideMaps = imo.getExternalOverrides();\n\n let referenceNode;\n\n if (!serverOnly) {\n const overridableImportMap = document.querySelector(\n 'script[type=\"overridable-importmap\"]',\n );\n\n referenceNode = overridableImportMap;\n\n if (!referenceNode) {\n const importMaps = document.querySelectorAll(\n `script[type=\"${importMapType}\"]`,\n );\n referenceNode = importMaps ? importMaps[importMaps.length - 1] : null;\n }\n\n if (overridableImportMap) {\n if (overridableImportMap.src) {\n throw Error(\n `import-map-overrides: external import maps with type=\"overridable-importmap\" are not supported`,\n );\n }\n let originalMap;\n try {\n originalMap = JSON.parse(overridableImportMap.textContent);\n } catch (e) {\n throw Error(\n `Invalid