Skip to content

Commit 9466eb8

Browse files
committed
gh-118201: Simplify conv_confname (#126089)
(cherry picked from commit c5c9286)
1 parent 3feebdd commit 9466eb8

File tree

6 files changed

+87
-111
lines changed

6 files changed

+87
-111
lines changed

Lib/test/support/os_helper.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,7 @@ def fd_count():
632632
if hasattr(os, 'sysconf'):
633633
try:
634634
MAXFD = os.sysconf("SC_OPEN_MAX")
635-
except (OSError, ValueError):
636-
# gh-118201: ValueError is raised intermittently on iOS
635+
except OSError:
637636
pass
638637

639638
old_modes = None

Lib/test/test_os.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2397,8 +2397,8 @@ def test_fchown(self):
23972397
support.is_emscripten or support.is_wasi,
23982398
"musl libc issue on Emscripten/WASI, bpo-46390"
23992399
)
2400-
@unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
24012400
def test_fpathconf(self):
2401+
self.assertIn("PC_NAME_MAX", os.pathconf_names)
24022402
self.check(os.pathconf, "PC_NAME_MAX")
24032403
self.check(os.fpathconf, "PC_NAME_MAX")
24042404
self.check_bool(os.pathconf, "PC_NAME_MAX")

Lib/test/test_posix.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,38 @@ def test_dup(self):
568568

569569
@unittest.skipUnless(hasattr(posix, 'confstr'),
570570
'test needs posix.confstr()')
571-
@unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
572571
def test_confstr(self):
573-
self.assertRaises(ValueError, posix.confstr, "CS_garbage")
574-
self.assertEqual(len(posix.confstr("CS_PATH")) > 0, True)
572+
with self.assertRaisesRegex(
573+
ValueError, "unrecognized configuration name"
574+
):
575+
posix.confstr("CS_garbage")
576+
577+
with self.assertRaisesRegex(
578+
TypeError, "configuration names must be strings or integers"
579+
):
580+
posix.confstr(1.23)
581+
582+
path = posix.confstr("CS_PATH")
583+
self.assertGreater(len(path), 0)
584+
self.assertEqual(posix.confstr(posix.confstr_names["CS_PATH"]), path)
585+
586+
@unittest.skipUnless(hasattr(posix, 'sysconf'),
587+
'test needs posix.sysconf()')
588+
def test_sysconf(self):
589+
with self.assertRaisesRegex(
590+
ValueError, "unrecognized configuration name"
591+
):
592+
posix.sysconf("SC_garbage")
593+
594+
with self.assertRaisesRegex(
595+
TypeError, "configuration names must be strings or integers"
596+
):
597+
posix.sysconf(1.23)
598+
599+
arg_max = posix.sysconf("SC_ARG_MAX")
600+
self.assertGreater(arg_max, 0)
601+
self.assertEqual(
602+
posix.sysconf(posix.sysconf_names["SC_ARG_MAX"]), arg_max)
575603

576604
@unittest.skipUnless(hasattr(posix, 'dup2'),
577605
'test needs posix.dup2()')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed intermittent failures of :any:`os.confstr`, :any:`os.pathconf` and
2+
:any:`os.sysconf` on iOS and Android.

Modules/clinic/posixmodule.c.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 47 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3078,18 +3078,22 @@ class Py_off_t_return_converter(long_return_converter):
30783078
type = 'Py_off_t'
30793079
conversion_fn = 'PyLong_FromPy_off_t'
30803080
3081-
class path_confname_converter(CConverter):
3081+
class confname_converter(CConverter):
30823082
type="int"
3083-
converter="conv_path_confname"
3083+
converter="conv_confname"
30843084
3085-
class confstr_confname_converter(path_confname_converter):
3086-
converter='conv_confstr_confname'
3085+
def converter_init(self, *, table):
3086+
self.table = table
30873087
3088-
class sysconf_confname_converter(path_confname_converter):
3089-
converter="conv_sysconf_confname"
3088+
def parse_arg(self, argname, displayname, *, limited_capi):
3089+
return self.format_code("""
3090+
if (!{converter}(module, {argname}, &{paramname}, "{table}")) {{{{
3091+
goto exit;
3092+
}}}}
3093+
""", argname=argname, converter=self.converter, table=self.table)
30903094
30913095
[python start generated code]*/
3092-
/*[python end generated code: output=da39a3ee5e6b4b0d input=577cb476e5d64960]*/
3096+
/*[python end generated code: output=da39a3ee5e6b4b0d input=a6199b1618d73f53]*/
30933097

30943098
/*[clinic input]
30953099
@@ -13503,46 +13507,38 @@ struct constdef {
1350313507
};
1350413508

1350513509
static int
13506-
conv_confname(PyObject *arg, int *valuep, struct constdef *table,
13507-
size_t tablesize)
13510+
conv_confname(PyObject *module, PyObject *arg, int *valuep, const char *tablename)
1350813511
{
13509-
if (PyLong_Check(arg)) {
13510-
int value = PyLong_AsInt(arg);
13511-
if (value == -1 && PyErr_Occurred())
13512-
return 0;
13513-
*valuep = value;
13514-
return 1;
13515-
}
13516-
else {
13517-
/* look up the value in the table using a binary search */
13518-
size_t lo = 0;
13519-
size_t mid;
13520-
size_t hi = tablesize;
13521-
int cmp;
13522-
const char *confname;
13523-
if (!PyUnicode_Check(arg)) {
13524-
PyErr_SetString(PyExc_TypeError,
13525-
"configuration names must be strings or integers");
13512+
if (PyUnicode_Check(arg)) {
13513+
PyObject *table = PyObject_GetAttrString(module, tablename);
13514+
if (table == NULL) {
1352613515
return 0;
1352713516
}
13528-
confname = PyUnicode_AsUTF8(arg);
13529-
if (confname == NULL)
13517+
13518+
arg = PyObject_GetItem(table, arg);
13519+
Py_DECREF(table);
13520+
if (arg == NULL) {
13521+
PyErr_SetString(
13522+
PyExc_ValueError, "unrecognized configuration name");
1353013523
return 0;
13531-
while (lo < hi) {
13532-
mid = (lo + hi) / 2;
13533-
cmp = strcmp(confname, table[mid].name);
13534-
if (cmp < 0)
13535-
hi = mid;
13536-
else if (cmp > 0)
13537-
lo = mid + 1;
13538-
else {
13539-
*valuep = table[mid].value;
13540-
return 1;
13541-
}
1354213524
}
13543-
PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
13544-
return 0;
13525+
} else {
13526+
Py_INCREF(arg); // Match the Py_DECREF below.
13527+
}
13528+
13529+
int success = 0;
13530+
if (!PyLong_Check(arg)) {
13531+
PyErr_SetString(PyExc_TypeError,
13532+
"configuration names must be strings or integers");
13533+
} else {
13534+
int value = PyLong_AsInt(arg);
13535+
if (!(value == -1 && PyErr_Occurred())) {
13536+
*valuep = value;
13537+
success = 1;
13538+
}
1354513539
}
13540+
Py_DECREF(arg);
13541+
return success;
1354613542
}
1354713543

1354813544

@@ -13633,14 +13629,6 @@ static struct constdef posix_constants_pathconf[] = {
1363313629
{"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
1363413630
#endif
1363513631
};
13636-
13637-
static int
13638-
conv_path_confname(PyObject *arg, int *valuep)
13639-
{
13640-
return conv_confname(arg, valuep, posix_constants_pathconf,
13641-
sizeof(posix_constants_pathconf)
13642-
/ sizeof(struct constdef));
13643-
}
1364413632
#endif
1364513633

1364613634

@@ -13649,7 +13637,7 @@ conv_path_confname(PyObject *arg, int *valuep)
1364913637
os.fpathconf -> long
1365013638
1365113639
fd: fildes
13652-
name: path_confname
13640+
name: confname(table="pathconf_names")
1365313641
/
1365413642
1365513643
Return the configuration limit name for the file descriptor fd.
@@ -13659,7 +13647,7 @@ If there is no limit, return -1.
1365913647

1366013648
static long
1366113649
os_fpathconf_impl(PyObject *module, int fd, int name)
13662-
/*[clinic end generated code: output=d5b7042425fc3e21 input=5b8d2471cfaae186]*/
13650+
/*[clinic end generated code: output=d5b7042425fc3e21 input=023d44589c9ed6aa]*/
1366313651
{
1366413652
long limit;
1366513653

@@ -13677,7 +13665,7 @@ os_fpathconf_impl(PyObject *module, int fd, int name)
1367713665
/*[clinic input]
1367813666
os.pathconf -> long
1367913667
path: path_t(allow_fd='PATH_HAVE_FPATHCONF')
13680-
name: path_confname
13668+
name: confname(table="pathconf_names")
1368113669
1368213670
Return the configuration limit name for the file or directory path.
1368313671
@@ -13688,7 +13676,7 @@ On some platforms, path may also be specified as an open file descriptor.
1368813676

1368913677
static long
1369013678
os_pathconf_impl(PyObject *module, path_t *path, int name)
13691-
/*[clinic end generated code: output=5bedee35b293a089 input=bc3e2a985af27e5e]*/
13679+
/*[clinic end generated code: output=5bedee35b293a089 input=6f6072f57b10c787]*/
1369213680
{
1369313681
long limit;
1369413682

@@ -13865,27 +13853,19 @@ static struct constdef posix_constants_confstr[] = {
1386513853
#endif
1386613854
};
1386713855

13868-
static int
13869-
conv_confstr_confname(PyObject *arg, int *valuep)
13870-
{
13871-
return conv_confname(arg, valuep, posix_constants_confstr,
13872-
sizeof(posix_constants_confstr)
13873-
/ sizeof(struct constdef));
13874-
}
13875-
1387613856

1387713857
/*[clinic input]
1387813858
os.confstr
1387913859
13880-
name: confstr_confname
13860+
name: confname(table="confstr_names")
1388113861
/
1388213862
1388313863
Return a string-valued system configuration variable.
1388413864
[clinic start generated code]*/
1388513865

1388613866
static PyObject *
1388713867
os_confstr_impl(PyObject *module, int name)
13888-
/*[clinic end generated code: output=bfb0b1b1e49b9383 input=18fb4d0567242e65]*/
13868+
/*[clinic end generated code: output=bfb0b1b1e49b9383 input=4c6ffca2837ec959]*/
1388913869
{
1389013870
PyObject *result = NULL;
1389113871
char buffer[255];
@@ -14422,26 +14402,18 @@ static struct constdef posix_constants_sysconf[] = {
1442214402
#endif
1442314403
};
1442414404

14425-
static int
14426-
conv_sysconf_confname(PyObject *arg, int *valuep)
14427-
{
14428-
return conv_confname(arg, valuep, posix_constants_sysconf,
14429-
sizeof(posix_constants_sysconf)
14430-
/ sizeof(struct constdef));
14431-
}
14432-
1443314405

1443414406
/*[clinic input]
1443514407
os.sysconf -> long
14436-
name: sysconf_confname
14408+
name: confname(table="sysconf_names")
1443714409
/
1443814410
1443914411
Return an integer-valued system configuration variable.
1444014412
[clinic start generated code]*/
1444114413

1444214414
static long
1444314415
os_sysconf_impl(PyObject *module, int name)
14444-
/*[clinic end generated code: output=3662f945fc0cc756 input=279e3430a33f29e4]*/
14416+
/*[clinic end generated code: output=3662f945fc0cc756 input=930b8f23b5d15086]*/
1444514417
{
1444614418
long value;
1444714419

@@ -14454,40 +14426,15 @@ os_sysconf_impl(PyObject *module, int name)
1445414426
#endif /* HAVE_SYSCONF */
1445514427

1445614428

14457-
/* This code is used to ensure that the tables of configuration value names
14458-
* are in sorted order as required by conv_confname(), and also to build
14459-
* the exported dictionaries that are used to publish information about the
14460-
* names available on the host platform.
14461-
*
14462-
* Sorting the table at runtime ensures that the table is properly ordered
14463-
* when used, even for platforms we're not able to test on. It also makes
14464-
* it easier to add additional entries to the tables.
14465-
*/
14466-
14467-
static int
14468-
cmp_constdefs(const void *v1, const void *v2)
14469-
{
14470-
const struct constdef *c1 =
14471-
(const struct constdef *) v1;
14472-
const struct constdef *c2 =
14473-
(const struct constdef *) v2;
14474-
14475-
return strcmp(c1->name, c2->name);
14476-
}
14477-
1447814429
static int
1447914430
setup_confname_table(struct constdef *table, size_t tablesize,
1448014431
const char *tablename, PyObject *module)
1448114432
{
14482-
PyObject *d = NULL;
14483-
size_t i;
14484-
14485-
qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs);
14486-
d = PyDict_New();
14433+
PyObject *d = PyDict_New();
1448714434
if (d == NULL)
1448814435
return -1;
1448914436

14490-
for (i=0; i < tablesize; ++i) {
14437+
for (size_t i=0; i < tablesize; ++i) {
1449114438
PyObject *o = PyLong_FromLong(table[i].value);
1449214439
if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) {
1449314440
Py_XDECREF(o);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy