use PyOS_double_to_string to prevent locale-specific behavior (#4982)

* use PyOS_double_to_string to prevent locale-specific behavior

* update

---------
This commit is contained in:
mdehoon
2025-03-26 17:58:08 +09:00
committed by GitHub
parent 180d8a6e69
commit 32b9648617
2 changed files with 99 additions and 35 deletions

View File

@ -1961,11 +1961,12 @@ Aligner_str(Aligner* self)
{ {
char text[1024]; char text[1024];
char* p = text; char* p = text;
char* value;
PyObject* substitution_matrix = self->substitution_matrix.obj; PyObject* substitution_matrix = self->substitution_matrix.obj;
void* args[3]; void* args[3];
int n = 0; int n = 0;
PyObject* wildcard = NULL; PyObject* wildcard = NULL;
PyObject* s; PyObject* s = NULL;
p += sprintf(p, "Pairwise sequence aligner with parameters\n"); p += sprintf(p, "Pairwise sequence aligner with parameters\n");
if (substitution_matrix) { if (substitution_matrix) {
@ -1983,44 +1984,88 @@ Aligner_str(Aligner* self)
p += sprintf(p, " wildcard: '%%U'\n"); p += sprintf(p, " wildcard: '%%U'\n");
args[n++] = wildcard; args[n++] = wildcard;
} }
p += sprintf(p, " match_score: %f\n", self->match); /* Use PyOS_double_to_string to ensure that the locale does
p += sprintf(p, " mismatch_score: %f\n", self->mismatch); * not change the decimal point into a comma.
*/
value = PyOS_double_to_string(self->match, 'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " match_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->mismatch, 'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " mismatch_score: %s\n", value);
PyMem_Free(value);
} }
if (self->insertion_score_function) { if (self->insertion_score_function) {
p += sprintf(p, " insertion_score_function: %%R\n"); p += sprintf(p, " insertion_score_function: %%R\n");
args[n++] = self->insertion_score_function; args[n++] = self->insertion_score_function;
} }
else { else {
p += sprintf(p, " open_internal_insertion_score: %f\n", value = PyOS_double_to_string(self->open_internal_insertion_score,
self->open_internal_insertion_score); 'f', 6, 0, NULL);
p += sprintf(p, " extend_internal_insertion_score: %f\n", if (!value) goto exit;
self->extend_internal_insertion_score); p += sprintf(p, " open_internal_insertion_score: %s\n", value);
p += sprintf(p, " open_left_insertion_score: %f\n", PyMem_Free(value);
self->open_left_insertion_score); value = PyOS_double_to_string(self->extend_internal_insertion_score,
p += sprintf(p, " extend_left_insertion_score: %f\n", 'f', 6, 0, NULL);
self->extend_left_insertion_score); if (!value) goto exit;
p += sprintf(p, " open_right_insertion_score: %f\n", p += sprintf(p, " extend_internal_insertion_score: %s\n", value);
self->open_right_insertion_score); PyMem_Free(value);
p += sprintf(p, " extend_right_insertion_score: %f\n", value = PyOS_double_to_string(self->open_left_insertion_score,
self->extend_right_insertion_score); 'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " open_left_insertion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->extend_left_insertion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " extend_left_insertion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->open_right_insertion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " open_right_insertion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->extend_right_insertion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " extend_right_insertion_score: %s\n", value);
PyMem_Free(value);
} }
if (self->deletion_score_function) { if (self->deletion_score_function) {
p += sprintf(p, " deletion_score_function: %%R\n"); p += sprintf(p, " deletion_score_function: %%R\n");
args[n++] = self->deletion_score_function; args[n++] = self->deletion_score_function;
} }
else { else {
p += sprintf(p, " open_internal_deletion_score: %f\n", value = PyOS_double_to_string(self->open_internal_deletion_score,
self->open_internal_deletion_score); 'f', 6, 0, NULL);
p += sprintf(p, " extend_internal_deletion_score: %f\n", if (!value) goto exit;
self->extend_internal_deletion_score); p += sprintf(p, " open_internal_deletion_score: %s\n", value);
p += sprintf(p, " open_left_deletion_score: %f\n", PyMem_Free(value);
self->open_left_deletion_score); value = PyOS_double_to_string(self->extend_internal_deletion_score,
p += sprintf(p, " extend_left_deletion_score: %f\n", 'f', 6, 0, NULL);
self->extend_left_deletion_score); p += sprintf(p, " extend_internal_deletion_score: %s\n", value);
p += sprintf(p, " open_right_deletion_score: %f\n", PyMem_Free(value);
self->open_right_deletion_score); value = PyOS_double_to_string(self->open_left_deletion_score,
p += sprintf(p, " extend_right_deletion_score: %f\n", 'f', 6, 0, NULL);
self->extend_right_deletion_score); if (!value) goto exit;
p += sprintf(p, " open_left_deletion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->extend_left_deletion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " extend_left_deletion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->open_right_deletion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " open_right_deletion_score: %s\n", value);
PyMem_Free(value);
value = PyOS_double_to_string(self->extend_right_deletion_score,
'f', 6, 0, NULL);
if (!value) goto exit;
p += sprintf(p, " extend_right_deletion_score: %s\n", value);
PyMem_Free(value);
} }
switch (self->mode) { switch (self->mode) {
case Global: sprintf(p, " mode: global\n"); break; case Global: sprintf(p, " mode: global\n"); break;
@ -2031,6 +2076,8 @@ Aligner_str(Aligner* self)
return NULL; return NULL;
} }
s = PyUnicode_FromFormat(text, args[0], args[1], args[2]); s = PyUnicode_FromFormat(text, args[0], args[1], args[2]);
exit:
Py_XDECREF(wildcard); Py_XDECREF(wildcard);
return s; return s;
} }

View File

@ -682,8 +682,15 @@ PyNode_repr(PyNode* self)
{ {
char string[64]; char string[64];
sprintf(string, "(%d, %d): %g", /* Use PyOS_double_to_string to ensure that the locale does
self->node.left, self->node.right, self->node.distance); * not change the decimal point into a comma.
*/
char* value = PyOS_double_to_string(self->node.distance, 'g', 6, 0, NULL);
if (!value) return NULL;
sprintf(string, "(%d, %d): %s", self->node.left, self->node.right, value);
PyMem_Free(value);
return PyUnicode_FromString(string); return PyUnicode_FromString(string);
} }
@ -928,15 +935,27 @@ PyTree_str(PyTree* self)
int i; int i;
const int n = self->n; const int n = self->n;
char string[128]; char string[128];
char* distance;
Node node; Node node;
PyObject* line; PyObject* line;
PyObject* output; PyObject* output;
PyObject* temp; PyObject* temp;
output = PyUnicode_FromString(""); output = PyUnicode_FromString("");
if (!output) return NULL;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
node = self->nodes[i]; node = self->nodes[i];
sprintf(string, "(%d, %d): %g", node.left, node.right, node.distance); distance = PyOS_double_to_string(node.distance, 'g', 6, 0, NULL);
if (!distance) {
Py_DECREF(output);
return NULL;
}
/* Use PyOS_double_to_string to ensure that the locale does
* not change the decimal point into a comma.
*/
sprintf(string, "(%d, %d): %s", node.left, node.right, distance);
PyMem_Free(distance);
if (i < n-1) strcat(string, "\n"); if (i < n-1) strcat(string, "\n");
line = PyUnicode_FromString(string); line = PyUnicode_FromString(string);
if (!line) { if (!line) {
@ -944,11 +963,9 @@ PyTree_str(PyTree* self)
return NULL; return NULL;
} }
temp = PyUnicode_Concat(output, line); temp = PyUnicode_Concat(output, line);
if (!temp) { Py_DECREF(line);
Py_DECREF(output); Py_DECREF(output);
Py_DECREF(line); if (!temp) return NULL;
return NULL;
}
output = temp; output = temp;
} }
return output; return output;