mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
bpo-34170: Cleanup pymain_read_conf() (GH-8476)
* Config: Rename ignore_environment field to use_environment. * _PyCoreConfig_Read(): if isolated is set, use_environment and site_import are now always set to 0. * Inline pymain_free_raw() into pymain_free() * Move config_init_warnoptions() call into pymain_read_conf_impl() * _PyCoreConfig_Read(): don't replace values if they are already set: faulthandler, pycache_prefix, home.
This commit is contained in:
parent
5473f061f5
commit
d145775b45
3 changed files with 71 additions and 74 deletions
|
|
@ -29,9 +29,14 @@ typedef struct {
|
||||||
/* Install signal handlers? Yes by default. */
|
/* Install signal handlers? Yes by default. */
|
||||||
int install_signal_handlers;
|
int install_signal_handlers;
|
||||||
|
|
||||||
int ignore_environment; /* -E, Py_IgnoreEnvironmentFlag, -1 means unset */
|
/* If greater than 0: use environment variables.
|
||||||
|
Set to 0 by -E command line option. If set to -1 (default), it is
|
||||||
|
set to !Py_IgnoreEnvironmentFlag. */
|
||||||
|
int use_environment;
|
||||||
|
|
||||||
int use_hash_seed; /* PYTHONHASHSEED=x */
|
int use_hash_seed; /* PYTHONHASHSEED=x */
|
||||||
unsigned long hash_seed;
|
unsigned long hash_seed;
|
||||||
|
|
||||||
const char *allocator; /* Memory allocator: PYTHONMALLOC */
|
const char *allocator; /* Memory allocator: PYTHONMALLOC */
|
||||||
int dev_mode; /* PYTHONDEVMODE, -X dev */
|
int dev_mode; /* PYTHONDEVMODE, -X dev */
|
||||||
|
|
||||||
|
|
@ -238,7 +243,7 @@ typedef struct {
|
||||||
#define _PyCoreConfig_INIT \
|
#define _PyCoreConfig_INIT \
|
||||||
(_PyCoreConfig){ \
|
(_PyCoreConfig){ \
|
||||||
.install_signal_handlers = 1, \
|
.install_signal_handlers = 1, \
|
||||||
.ignore_environment = -1, \
|
.use_environment = -1, \
|
||||||
.use_hash_seed = -1, \
|
.use_hash_seed = -1, \
|
||||||
.faulthandler = -1, \
|
.faulthandler = -1, \
|
||||||
.tracemalloc = -1, \
|
.tracemalloc = -1, \
|
||||||
|
|
|
||||||
106
Modules/main.c
106
Modules/main.c
|
|
@ -169,9 +169,9 @@ pymain_usage(int error, const wchar_t* program)
|
||||||
static const char*
|
static const char*
|
||||||
config_get_env_var(const _PyCoreConfig *config, const char *name)
|
config_get_env_var(const _PyCoreConfig *config, const char *name)
|
||||||
{
|
{
|
||||||
assert(config->ignore_environment >= 0);
|
assert(config->use_environment >= 0);
|
||||||
|
|
||||||
if (config->ignore_environment) {
|
if (!config->use_environment) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,9 +188,9 @@ config_get_env_var(const _PyCoreConfig *config, const char *name)
|
||||||
static int
|
static int
|
||||||
config_get_env_var_dup(const _PyCoreConfig *config, wchar_t **dest, wchar_t *wname, char *name)
|
config_get_env_var_dup(const _PyCoreConfig *config, wchar_t **dest, wchar_t *wname, char *name)
|
||||||
{
|
{
|
||||||
assert(config->ignore_environment >= 0);
|
assert(config->use_environment >= 0);
|
||||||
|
|
||||||
if (config->ignore_environment) {
|
if (!config->use_environment) {
|
||||||
*dest = NULL;
|
*dest = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -557,7 +557,6 @@ _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
|
||||||
config->ATTR = !(VALUE); \
|
config->ATTR = !(VALUE); \
|
||||||
}
|
}
|
||||||
|
|
||||||
COPY_FLAG(ignore_environment, Py_IgnoreEnvironmentFlag);
|
|
||||||
COPY_FLAG(utf8_mode, Py_UTF8Mode);
|
COPY_FLAG(utf8_mode, Py_UTF8Mode);
|
||||||
COPY_FLAG(isolated, Py_IsolatedFlag);
|
COPY_FLAG(isolated, Py_IsolatedFlag);
|
||||||
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
|
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
|
||||||
|
|
@ -573,6 +572,7 @@ _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
|
||||||
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
|
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
|
||||||
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
|
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
|
||||||
COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
|
COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
|
||||||
COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
|
COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
|
||||||
|
|
@ -599,7 +599,6 @@ _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config)
|
||||||
VAR = !config->ATTR; \
|
VAR = !config->ATTR; \
|
||||||
}
|
}
|
||||||
|
|
||||||
COPY_FLAG(ignore_environment, Py_IgnoreEnvironmentFlag);
|
|
||||||
COPY_FLAG(utf8_mode, Py_UTF8Mode);
|
COPY_FLAG(utf8_mode, Py_UTF8Mode);
|
||||||
COPY_FLAG(isolated, Py_IsolatedFlag);
|
COPY_FLAG(isolated, Py_IsolatedFlag);
|
||||||
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
|
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
|
||||||
|
|
@ -615,6 +614,7 @@ _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config)
|
||||||
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
|
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
|
||||||
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
|
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
|
||||||
COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
|
COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag);
|
||||||
COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
|
COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory);
|
||||||
|
|
@ -702,7 +702,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
COPY_ATTR(install_signal_handlers);
|
COPY_ATTR(install_signal_handlers);
|
||||||
COPY_ATTR(ignore_environment);
|
COPY_ATTR(use_environment);
|
||||||
COPY_ATTR(use_hash_seed);
|
COPY_ATTR(use_hash_seed);
|
||||||
COPY_ATTR(hash_seed);
|
COPY_ATTR(hash_seed);
|
||||||
COPY_ATTR(_install_importlib);
|
COPY_ATTR(_install_importlib);
|
||||||
|
|
@ -818,7 +818,7 @@ pymain_clear_config(_PyCoreConfig *config)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pymain_free_raw(_PyMain *pymain)
|
pymain_free(_PyMain *pymain)
|
||||||
{
|
{
|
||||||
_PyImport_Fini2();
|
_PyImport_Fini2();
|
||||||
|
|
||||||
|
|
@ -839,13 +839,6 @@ pymain_free_raw(_PyMain *pymain)
|
||||||
orig_argv = NULL;
|
orig_argv = NULL;
|
||||||
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
pymain_free(_PyMain *pymain)
|
|
||||||
{
|
|
||||||
pymain_free_raw(pymain);
|
|
||||||
|
|
||||||
#ifdef __INSURE__
|
#ifdef __INSURE__
|
||||||
/* Insure++ is a memory analysis tool that aids in discovering
|
/* Insure++ is a memory analysis tool that aids in discovering
|
||||||
|
|
@ -1002,9 +995,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
config->ignore_environment++;
|
|
||||||
config->isolated++;
|
config->isolated++;
|
||||||
config->user_site_directory = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case 'J': reserved for Jython */
|
/* case 'J': reserved for Jython */
|
||||||
|
|
@ -1026,7 +1017,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
config->ignore_environment++;
|
config->use_environment = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
|
|
@ -1246,10 +1237,9 @@ config_init_warnoptions(_PyCoreConfig *config, _PyCmdline *cmdline)
|
||||||
Return 0 on success.
|
Return 0 on success.
|
||||||
Set pymain->err and return -1 on error. */
|
Set pymain->err and return -1 on error. */
|
||||||
static _PyInitError
|
static _PyInitError
|
||||||
cmdline_init_env_warnoptions(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdline)
|
cmdline_init_env_warnoptions(_PyMain *pymain, const _PyCoreConfig *config,
|
||||||
|
_PyCmdline *cmdline)
|
||||||
{
|
{
|
||||||
assert(!config->ignore_environment);
|
|
||||||
|
|
||||||
wchar_t *env;
|
wchar_t *env;
|
||||||
int res = config_get_env_var_dup(config, &env,
|
int res = config_get_env_var_dup(config, &env,
|
||||||
L"PYTHONWARNINGS", "PYTHONWARNINGS");
|
L"PYTHONWARNINGS", "PYTHONWARNINGS");
|
||||||
|
|
@ -1728,10 +1718,6 @@ pymain_init_tracemalloc(_PyCoreConfig *config)
|
||||||
int nframe;
|
int nframe;
|
||||||
int valid;
|
int valid;
|
||||||
|
|
||||||
if (config->tracemalloc >= 0) {
|
|
||||||
return _Py_INIT_OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *env = config_get_env_var(config, "PYTHONTRACEMALLOC");
|
const char *env = config_get_env_var(config, "PYTHONTRACEMALLOC");
|
||||||
if (env) {
|
if (env) {
|
||||||
if (!pymain_str_to_int(env, &nframe)) {
|
if (!pymain_str_to_int(env, &nframe)) {
|
||||||
|
|
@ -1866,12 +1852,6 @@ config_init_hash_seed(_PyCoreConfig *config)
|
||||||
static _PyInitError
|
static _PyInitError
|
||||||
config_init_utf8_mode(_PyCoreConfig *config)
|
config_init_utf8_mode(_PyCoreConfig *config)
|
||||||
{
|
{
|
||||||
/* The option was already set in config.Py_UTF8Mode,
|
|
||||||
by Py_LegacyWindowsFSEncodingFlag or PYTHONLEGACYWINDOWSFSENCODING. */
|
|
||||||
if (config->utf8_mode >= 0) {
|
|
||||||
return _Py_INIT_OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
const wchar_t *xopt = config_get_xoption(config, L"utf8");
|
const wchar_t *xopt = config_get_xoption(config, L"utf8");
|
||||||
if (xopt) {
|
if (xopt) {
|
||||||
wchar_t *sep = wcschr(xopt, L'=');
|
wchar_t *sep = wcschr(xopt, L'=');
|
||||||
|
|
@ -1915,7 +1895,7 @@ config_init_utf8_mode(_PyCoreConfig *config)
|
||||||
static _PyInitError
|
static _PyInitError
|
||||||
config_read_env_vars(_PyCoreConfig *config)
|
config_read_env_vars(_PyCoreConfig *config)
|
||||||
{
|
{
|
||||||
assert(!config->ignore_environment);
|
assert(config->use_environment > 0);
|
||||||
|
|
||||||
/* Get environment variables */
|
/* Get environment variables */
|
||||||
get_env_flag(config, &config->debug, "PYTHONDEBUG");
|
get_env_flag(config, &config->debug, "PYTHONDEBUG");
|
||||||
|
|
@ -1987,10 +1967,12 @@ static _PyInitError
|
||||||
config_read_complex_options(_PyCoreConfig *config)
|
config_read_complex_options(_PyCoreConfig *config)
|
||||||
{
|
{
|
||||||
/* More complex options configured by env var and -X option */
|
/* More complex options configured by env var and -X option */
|
||||||
|
if (config->faulthandler < 0) {
|
||||||
if (config_get_env_var(config, "PYTHONFAULTHANDLER")
|
if (config_get_env_var(config, "PYTHONFAULTHANDLER")
|
||||||
|| config_get_xoption(config, L"faulthandler")) {
|
|| config_get_xoption(config, L"faulthandler")) {
|
||||||
config->faulthandler = 1;
|
config->faulthandler = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (config_get_env_var(config, "PYTHONPROFILEIMPORTTIME")
|
if (config_get_env_var(config, "PYTHONPROFILEIMPORTTIME")
|
||||||
|| config_get_xoption(config, L"importtime")) {
|
|| config_get_xoption(config, L"importtime")) {
|
||||||
config->import_time = 1;
|
config->import_time = 1;
|
||||||
|
|
@ -2001,16 +1983,20 @@ config_read_complex_options(_PyCoreConfig *config)
|
||||||
config->dev_mode = 1;
|
config->dev_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_PyInitError err = pymain_init_tracemalloc(config);
|
_PyInitError err;
|
||||||
|
if (config->tracemalloc < 0) {
|
||||||
|
err = pymain_init_tracemalloc(config);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->pycache_prefix == NULL) {
|
||||||
err = pymain_init_pycache_prefix(config);
|
err = pymain_init_pycache_prefix(config);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return _Py_INIT_OK();
|
return _Py_INIT_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2036,8 +2022,14 @@ pymain_read_conf_impl(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(config->ignore_environment >= 0);
|
err = _PyCoreConfig_Read(config);
|
||||||
if (!config->ignore_environment) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
|
pymain->err = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(config->use_environment >= 0);
|
||||||
|
if (config->use_environment) {
|
||||||
err = cmdline_init_env_warnoptions(pymain, config, cmdline);
|
err = cmdline_init_env_warnoptions(pymain, config, cmdline);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
pymain->err = err;
|
pymain->err = err;
|
||||||
|
|
@ -2045,7 +2037,7 @@ pymain_read_conf_impl(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = _PyCoreConfig_Read(config);
|
err = config_init_warnoptions(config, cmdline);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
pymain->err = err;
|
pymain->err = err;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -2135,8 +2127,8 @@ pymain_read_conf(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the configuration before reading the configuration,
|
/* Reset the configuration before reading again the configuration,
|
||||||
except UTF-8 Mode. */
|
just keep UTF-8 Mode value. */
|
||||||
int new_utf8_mode = config->utf8_mode;
|
int new_utf8_mode = config->utf8_mode;
|
||||||
if (_PyCoreConfig_Copy(config, &save_config) < 0) {
|
if (_PyCoreConfig_Copy(config, &save_config) < 0) {
|
||||||
pymain->err = _Py_INIT_NO_MEMORY();
|
pymain->err = _Py_INIT_NO_MEMORY();
|
||||||
|
|
@ -2157,7 +2149,6 @@ done:
|
||||||
setlocale(LC_ALL, oldloc);
|
setlocale(LC_ALL, oldloc);
|
||||||
PyMem_RawFree(oldloc);
|
PyMem_RawFree(oldloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2201,8 +2192,19 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
|
||||||
|
|
||||||
_PyCoreConfig_GetGlobalConfig(config);
|
_PyCoreConfig_GetGlobalConfig(config);
|
||||||
|
|
||||||
assert(config->ignore_environment >= 0);
|
if (config->isolated > 0) {
|
||||||
if (!config->ignore_environment) {
|
config->use_environment = 0;
|
||||||
|
config->user_site_directory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (config->legacy_windows_fs_encoding) {
|
||||||
|
config->utf8_mode = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(config->use_environment >= 0);
|
||||||
|
if (config->use_environment) {
|
||||||
err = config_read_env_vars(config);
|
err = config_read_env_vars(config);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -2222,15 +2224,19 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config->utf8_mode < 0) {
|
||||||
err = config_init_utf8_mode(config);
|
err = config_init_utf8_mode(config);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->home == NULL) {
|
||||||
err = config_init_home(config);
|
err = config_init_home(config);
|
||||||
if (_Py_INIT_FAILED(err)) {
|
if (_Py_INIT_FAILED(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config->program_name == NULL) {
|
if (config->program_name == NULL) {
|
||||||
err = config_init_program_name(config);
|
err = config_init_program_name(config);
|
||||||
|
|
@ -2248,7 +2254,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* options side effects */
|
/* default values */
|
||||||
if (config->dev_mode) {
|
if (config->dev_mode) {
|
||||||
if (config->faulthandler < 0) {
|
if (config->faulthandler < 0) {
|
||||||
config->faulthandler = 1;
|
config->faulthandler = 1;
|
||||||
|
|
@ -2257,14 +2263,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
|
||||||
config->allocator = "debug";
|
config->allocator = "debug";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
|
||||||
if (config->legacy_windows_fs_encoding) {
|
|
||||||
config->utf8_mode = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* default values */
|
|
||||||
if (config->use_hash_seed < 0) {
|
if (config->use_hash_seed < 0) {
|
||||||
config->use_hash_seed = 0;
|
config->use_hash_seed = 0;
|
||||||
config->hash_seed = 0;
|
config->hash_seed = 0;
|
||||||
|
|
@ -2547,12 +2545,6 @@ pymain_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
orig_argc = pymain->argc;
|
orig_argc = pymain->argc;
|
||||||
|
|
||||||
_PyInitError err = config_init_warnoptions(config, cmdline);
|
|
||||||
if (_Py_INIT_FAILED(err)) {
|
|
||||||
pymain->err = err;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ main(int argc, char *argv[])
|
||||||
_PyCoreConfig config = _PyCoreConfig_INIT;
|
_PyCoreConfig config = _PyCoreConfig_INIT;
|
||||||
config.user_site_directory = 0;
|
config.user_site_directory = 0;
|
||||||
config.site_import = 0;
|
config.site_import = 0;
|
||||||
config.ignore_environment = 1;
|
config.use_environment = 0;
|
||||||
config.program_name = L"./_freeze_importlib";
|
config.program_name = L"./_freeze_importlib";
|
||||||
/* Don't install importlib, since it could execute outdated bytecode. */
|
/* Don't install importlib, since it could execute outdated bytecode. */
|
||||||
config._install_importlib = 0;
|
config._install_importlib = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue