Add version file (#1087)

This commit is contained in:
Fábio Rosado
2023-01-03 17:31:13 +00:00
committed by GitHub
parent dbdcd0b3d0
commit 412da2de08
6 changed files with 48 additions and 63 deletions

View File

@@ -1,48 +1,24 @@
import { FetchError, ErrorCode } from "./exceptions";
import { FetchError, ErrorCode } from './exceptions';
/*
This is a fetch wrapper that handles any non 200 response and throws a FetchError
with the right ErrorCode.
TODO: Should we only throw on 4xx and 5xx responses?
*/
export async function robustFetch(url: string, options?: RequestInit): Promise<Response> {
const response = await fetch(url, options);
// Note that response.ok is true for 200-299 responses
if (!response.ok) {
const errorMsg = `Fetching from URL ${url} failed with error ${response.status} (${response.statusText}).`;
switch(response.status) {
switch (response.status) {
case 404:
throw new FetchError(
ErrorCode.FETCH_NOT_FOUND_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_NOT_FOUND_ERROR, errorMsg);
case 401:
throw new FetchError(
ErrorCode.FETCH_UNAUTHORIZED_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_UNAUTHORIZED_ERROR, errorMsg);
case 403:
throw new FetchError(
ErrorCode.FETCH_FORBIDDEN_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_FORBIDDEN_ERROR, errorMsg);
case 500:
throw new FetchError(
ErrorCode.FETCH_SERVER_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_SERVER_ERROR, errorMsg);
case 503:
throw new FetchError(
ErrorCode.FETCH_UNAVAILABLE_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_UNAVAILABLE_ERROR, errorMsg);
default:
throw new FetchError(
ErrorCode.FETCH_ERROR,
errorMsg
);
throw new FetchError(ErrorCode.FETCH_ERROR, errorMsg);
}
}
return response
return response;
}

View File

@@ -3,7 +3,7 @@ import './styles/pyscript_base.css';
import { loadConfigFromElement } from './pyconfig';
import type { AppConfig } from './pyconfig';
import type { Runtime } from './runtime';
import { version } from './runtime';
import { version } from './version';
import { PluginManager, define_custom_element } from './plugin';
import { make_PyScript, initHandlers, mountElements } from './components/pyscript';
import { PyodideRuntime } from './pyodide';
@@ -11,7 +11,7 @@ import { getLogger } from './logger';
import { handleFetchError, showWarning, globalExport } from './utils';
import { calculatePaths } from './plugins/fetch';
import { createCustomElements } from './components/elements';
import { UserError, ErrorCode, _createAlertBanner } from "./exceptions"
import { UserError, ErrorCode, _createAlertBanner } from './exceptions';
import { type Stdio, StdioMultiplexer, DEFAULT_STDIO } from './stdio';
import { PyTerminalPlugin } from './plugins/pyterminal';
import { SplashscreenPlugin } from './plugins/splashscreen';
@@ -180,7 +180,7 @@ export class PyScriptApp {
this.plugins.afterSetup(runtime);
//Refresh module cache in case plugins have modified the filesystem
runtime.invalidate_module_path_cache()
runtime.invalidate_module_path_cache();
this.logStatus('Executing <py-script> tags...');
this.executeScripts(runtime);
@@ -208,7 +208,7 @@ export class PyScriptApp {
// Save and load pyscript.py from FS
runtime.interpreter.FS.writeFile('pyscript.py', pyscript, { encoding: 'utf8' });
//Refresh the module cache so Python consistently finds pyscript module
runtime.invalidate_module_path_cache()
runtime.invalidate_module_path_cache();
// inject `define_custom_element` and showWarning it into the PyScript
// module scope
@@ -224,7 +224,7 @@ export class PyScriptApp {
import pyscript
from pyscript import Element, display, HTML
pyscript._install_deprecated_globals_2022_12_1(globals())
`)
`);
if (this.config.packages) {
logger.info('Packages to install: ', this.config.packages);
@@ -233,7 +233,7 @@ export class PyScriptApp {
await this.fetchPaths(runtime);
//This may be unnecessary - only useful if plugins try to import files fetch'd in fetchPaths()
runtime.invalidate_module_path_cache()
runtime.invalidate_module_path_cache();
// Finally load plugins
await this.fetchPythonPlugins(runtime);
}
@@ -282,7 +282,7 @@ export class PyScriptApp {
await runtime.loadFromFile(destPath, singleFile);
//refresh module cache before trying to import module files into runtime
runtime.invalidate_module_path_cache()
runtime.invalidate_module_path_cache();
const modulename = singleFile.replace(/^.*[\\/]/, '').replace('.py', '');

View File

@@ -1,8 +1,8 @@
import toml from '../src/toml';
import { getLogger } from './logger';
import { version } from './runtime';
import { version } from './version';
import { getAttribute, readTextFromPath, htmlDecode } from './utils';
import { UserError, ErrorCode } from "./exceptions"
import { UserError, ErrorCode } from './exceptions';
const logger = getLogger('py-config');
@@ -146,7 +146,7 @@ function parseConfig(configText: string, configType = 'toml') {
if (configText.trim()[0] === '{') {
throw new UserError(
ErrorCode.BAD_CONFIG,
`The config supplied: ${configText} is an invalid TOML and cannot be parsed`
`The config supplied: ${configText} is an invalid TOML and cannot be parsed`,
);
}
return toml.parse(configText);
@@ -154,7 +154,7 @@ function parseConfig(configText: string, configType = 'toml') {
const errMessage: string = err.toString();
throw new UserError(
ErrorCode.BAD_CONFIG,
`The config supplied: ${configText} is an invalid TOML and cannot be parsed: ${errMessage}`
`The config supplied: ${configText} is an invalid TOML and cannot be parsed: ${errMessage}`,
);
}
} else if (configType === 'json') {
@@ -170,7 +170,7 @@ function parseConfig(configText: string, configType = 'toml') {
} else {
throw new UserError(
ErrorCode.BAD_CONFIG,
`The type of config supplied '${configType}' is not supported, supported values are ["toml", "json"]`
`The type of config supplied '${configType}' is not supported, supported values are ["toml", "json"]`,
);
}
}

View File

@@ -4,10 +4,6 @@ import { getLogger } from './logger';
const logger = getLogger('pyscript/runtime');
// VERSION
// Version number of release
export const version = '2022.12.1.dev';
export type RuntimeInterpreter = PyodideInterface | null;
/*

10
pyscriptjs/src/version.ts Normal file
View File

@@ -0,0 +1,10 @@
/**
* @fileoverview Version of pyscript
* The version is based on calver which contains YEAR.MONTH.DAY.MODIFIER.
* The Modifier can be an optional text tag, such as "dev", "rc", etc.
*
* We are adding this file because we can't add version in main.js due to
* circular imports.
*/
export const version = '2022.12.1.dev';

View File

@@ -1,7 +1,7 @@
import { jest, describe, it, expect, } from '@jest/globals';
import { jest, describe, it, expect } from '@jest/globals';
import { loadConfigFromElement, defaultConfig } from '../../src/pyconfig';
import { version } from '../../src/runtime';
import { UserError } from '../../src/exceptions'
import { version } from '../../src/version';
import { UserError } from '../../src/exceptions';
// inspired by trump typos
const covfefeConfig = {
@@ -27,7 +27,6 @@ name = "covfefe"
lang = "covfefe"
`;
// ideally, I would like to be able to just do "new HTMLElement" in the tests
// below, but it is not permitted. The easiest work around is to create a fake
// custom element: not that we are not using any specific feature of custom
@@ -48,7 +47,6 @@ function make_config_element(attrs) {
return el;
}
describe('loadConfigFromElement', () => {
const xhrMockClass = () => ({
open: jest.fn(),
@@ -92,7 +90,6 @@ describe('loadConfigFromElement', () => {
expect(config.schema_version).toBe(1);
});
it('should load the JSON config from both inline and src', () => {
const el = make_config_element({ type: 'json', src: '/covfefe.json' });
el.innerHTML = JSON.stringify({ version: '0.2a', wonderful: 'hijacked' });
@@ -123,42 +120,48 @@ describe('loadConfigFromElement', () => {
it('should NOT be able to load an inline config in JSON format with type as TOML', () => {
const el = make_config_element({});
el.innerHTML = JSON.stringify(covfefeConfig);
expect(()=>loadConfigFromElement(el)).toThrow(/config supplied: {.*} is an invalid TOML and cannot be parsed/);
expect(() => loadConfigFromElement(el)).toThrow(
/config supplied: {.*} is an invalid TOML and cannot be parsed/,
);
});
it('should NOT be able to load an inline config in TOML format with type as JSON', () => {
const el = make_config_element({ type: 'json' });
el.innerHTML = covfefeConfigToml;
expect(()=>loadConfigFromElement(el)).toThrow(UserError);
expect(() => loadConfigFromElement(el)).toThrow(UserError);
});
it('should NOT be able to load an inline TOML config with a JSON config from src with type as toml', () => {
const el = make_config_element({ src: '/covfefe.json' });
el.innerHTML = covfefeConfigToml;
expect(()=>loadConfigFromElement(el)).toThrow(/config supplied: {.*} is an invalid TOML and cannot be parsed/);
expect(() => loadConfigFromElement(el)).toThrow(
/config supplied: {.*} is an invalid TOML and cannot be parsed/,
);
});
it('should NOT be able to load an inline TOML config with a JSON config from src with type as json', () => {
const el = make_config_element({ type: 'json', src: '/covfefe.json' });
el.innerHTML = covfefeConfigToml;
expect(()=>loadConfigFromElement(el)).toThrow(UserError);
expect(() => loadConfigFromElement(el)).toThrow(UserError);
});
it('should error out when passing an invalid JSON', () => {
const el = make_config_element({ type: 'json' });
el.innerHTML = '[[';
expect(()=>loadConfigFromElement(el)).toThrow(UserError);
expect(() => loadConfigFromElement(el)).toThrow(UserError);
});
it('should error out when passing an invalid TOML', () => {
const el = make_config_element({});
el.innerHTML = '[[';
expect(()=>loadConfigFromElement(el)).toThrow(UserError);
expect(() => loadConfigFromElement(el)).toThrow(UserError);
});
it('should not escape characters like &', () => {
const el = make_config_element({ type: 'json'});
el.innerHTML = JSON.stringify({ fetch: [{from: 'https://datausa.io/api/data?drilldowns=Nation&measures=Population'}]});
const el = make_config_element({ type: 'json' });
el.innerHTML = JSON.stringify({
fetch: [{ from: 'https://datausa.io/api/data?drilldowns=Nation&measures=Population' }],
});
const config = loadConfigFromElement(el);
expect(config.fetch[0].from).toBe('https://datausa.io/api/data?drilldowns=Nation&measures=Population');
});