Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
root = true

[*.{py,c,cpp,h,js,rst,md,yml,yaml}]
[*.{py,c,cpp,h,js,rst,md,yml,yaml,gram}]
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space

[*.{py,c,cpp,h}]
[*.{py,c,cpp,h,gram}]
indent_size = 4

[*.rst]
Expand Down
8 changes: 4 additions & 4 deletions Doc/library/venv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ The :mod:`!venv` module supports creating lightweight "virtual environments",
each with their own independent set of Python packages installed in
their :mod:`site` directories.
A virtual environment is created on top of an existing
Python installation, known as the virtual environment's "base" Python, and may
optionally be isolated from the packages in the base environment,
so only those explicitly installed in the virtual environment are available.
See :ref:`sys-path-init-virtual-environments` and :mod:`site`'s
Python installation, known as the virtual environment's "base" Python, and by
default is isolated from the packages in the base environment,
so that only those explicitly installed in the virtual environment are
available. See :ref:`sys-path-init-virtual-environments` and :mod:`site`'s
:ref:`virtual environments documentation <site-virtual-environments-configuration>`
for more information.

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ def skip_android_selinux(name):
is_wasi = sys.platform == "wasi"

def skip_emscripten_stack_overflow():
return unittest.skipIf(is_emscripten, "Exhausts limited stack on Emscripten")
return unittest.skipIf(is_emscripten, "Exhausts stack on Emscripten")

def skip_wasi_stack_overflow():
return unittest.skipIf(is_wasi, "Exhausts stack on WASI")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3942,7 +3942,7 @@ def __del__(self):
# it as a leak.
del C.__del__

@unittest.skipIf(support.is_emscripten, "Seems to works in Pyodide?")
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_slots_trash(self):
# Testing slot trash...
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_fstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -1651,6 +1651,18 @@ def __repr__(self):
self.assertEqual(f"{1+2 = # my comment
}", '1+2 = \n 3')

self.assertEqual(f'{""" # booo
"""=}', '""" # booo\n """=\' # booo\\n \'')

self.assertEqual(f'{" # nooo "=}', '" # nooo "=\' # nooo \'')
self.assertEqual(f'{" \" # nooo \" "=}', '" \\" # nooo \\" "=\' " # nooo " \'')

self.assertEqual(f'{ # some comment goes here
"""hello"""=}', ' \n """hello"""=\'hello\'')
self.assertEqual(f'{"""# this is not a comment
a""" # this is a comment
}', '# this is not a comment\n a')

# These next lines contains tabs. Backslash escapes don't
# work in f-strings.
# patchcheck doesn't like these tabs. So the only way to test
Expand Down
6 changes: 2 additions & 4 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -1918,11 +1918,9 @@ def test_makedir(self):
support.is_wasi,
"WASI's umask is a stub."
)
@unittest.skipIf(
support.is_emscripten,
"TODO: Fails in buildbot; see #135783"
)
def test_mode(self):
# Note: in some cases, the umask might already be 2 in which case this
# will pass even if os.umask is actually broken.
with os_helper.temp_umask(0o002):
base = os_helper.TESTFN
parent = os.path.join(base, 'dir1')
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_xml_etree_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_del_attribute(self):
self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})

@support.skip_wasi_stack_overflow()
@unittest.skipIf(support.is_emscripten, "segfaults")
@support.skip_emscripten_stack_overflow()
def test_trashcan(self):
# If this test fails, it will most likely die via segfault.
e = root = cET.Element('root')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed a bug where f-string debug expressions (using =) would incorrectly
strip out parts of strings containing escaped quotes and # characters. Patch
by Pablo Galindo.
4 changes: 2 additions & 2 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3477,12 +3477,12 @@ Change the current working directory to the specified path.

path may always be specified as a string.
On some platforms, path may also be specified as an open file descriptor.
If this functionality is unavailable, using it raises an exception.
If this functionality is unavailable, using it raises an exception.
[clinic start generated code]*/

static PyObject *
os_chdir_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=3be6400eee26eaae input=1a4a15b4d12cb15d]*/
/*[clinic end generated code: output=3be6400eee26eaae input=a74ceab5d72adf74]*/
{
int result;

Expand Down
88 changes: 68 additions & 20 deletions Parser/lexer/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,38 +121,88 @@ set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
}
PyObject *res = NULL;

// Check if there is a # character in the expression
// Look for a # character outside of string literals
int hash_detected = 0;
int in_string = 0;
char quote_char = 0;

for (Py_ssize_t i = 0; i < tok_mode->last_expr_size - tok_mode->last_expr_end; i++) {
if (tok_mode->last_expr_buffer[i] == '#') {
char ch = tok_mode->last_expr_buffer[i];

// Skip escaped characters
if (ch == '\\') {
i++;
continue;
}

// Handle quotes
if (ch == '"' || ch == '\'') {
// The following if/else block works becase there is an off number
// of quotes in STRING tokens and the lexer only ever reaches this
// function with valid STRING tokens.
// For example: """hello"""
// First quote: in_string = 1
// Second quote: in_string = 0
// Third quote: in_string = 1
if (!in_string) {
in_string = 1;
quote_char = ch;
}
else if (ch == quote_char) {
in_string = 0;
}
continue;
}

// Check for # outside strings
if (ch == '#' && !in_string) {
hash_detected = 1;
break;
}
}

// If we found a # character in the expression, we need to handle comments
if (hash_detected) {
Py_ssize_t input_length = tok_mode->last_expr_size - tok_mode->last_expr_end;
char *result = (char *)PyMem_Malloc((input_length + 1) * sizeof(char));
// Allocate buffer for processed result
char *result = (char *)PyMem_Malloc((tok_mode->last_expr_size - tok_mode->last_expr_end + 1) * sizeof(char));
if (!result) {
return -1;
}

Py_ssize_t i = 0;
Py_ssize_t j = 0;
Py_ssize_t i = 0; // Input position
Py_ssize_t j = 0; // Output position
in_string = 0; // Whether we're in a string
quote_char = 0; // Current string quote char

for (i = 0, j = 0; i < input_length; i++) {
if (tok_mode->last_expr_buffer[i] == '#') {
// Skip characters until newline or end of string
while (i < input_length && tok_mode->last_expr_buffer[i] != '\0') {
if (tok_mode->last_expr_buffer[i] == '\n') {
result[j++] = tok_mode->last_expr_buffer[i];
break;
}
// Process each character
while (i < tok_mode->last_expr_size - tok_mode->last_expr_end) {
char ch = tok_mode->last_expr_buffer[i];

// Handle string quotes
if (ch == '"' || ch == '\'') {
// See comment above to understand this part
if (!in_string) {
in_string = 1;
quote_char = ch;
} else if (ch == quote_char) {
in_string = 0;
}
result[j++] = ch;
}
// Skip comments
else if (ch == '#' && !in_string) {
while (i < tok_mode->last_expr_size - tok_mode->last_expr_end &&
tok_mode->last_expr_buffer[i] != '\n') {
i++;
}
} else {
result[j++] = tok_mode->last_expr_buffer[i];
if (i < tok_mode->last_expr_size - tok_mode->last_expr_end) {
result[j++] = '\n';
}
}
// Copy other chars
else {
result[j++] = ch;
}
i++;
}

result[j] = '\0'; // Null-terminate the result string
Expand All @@ -164,11 +214,9 @@ set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
tok_mode->last_expr_size - tok_mode->last_expr_end,
NULL
);

}


if (!res) {
if (!res) {
return -1;
}
token->metadata = res;
Expand Down
22 changes: 21 additions & 1 deletion Python/emscripten_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// defined with weak linkage so we can override it.
EM_JS(int, __syscall_getuid32_js, (void), {
// If we're in node and we can, report the native uid
if (typeof process !== "undefined" && typeof process.getuid === "function") {
if (ENVIRONMENT_IS_NODE) {
return process.getuid();
}
// Fall back to the stub case of returning 0.
Expand All @@ -17,3 +17,23 @@ EM_JS(int, __syscall_getuid32_js, (void), {
int __syscall_getuid32(void) {
return __syscall_getuid32_js();
}

EM_JS(int, __syscall_umask_js, (int mask), {
// If we're in node and we can, call native process.umask()
if (ENVIRONMENT_IS_NODE) {
try {
return process.umask(mask);
} catch(e) {
// oops...
// NodeJS docs: "In Worker threads, process.umask(mask) will throw an exception."
// umask docs: "This system call always succeeds"
return 0;
}
}
// Fall back to the stub case of returning 0.
return 0;
})

int __syscall_umask(int mask) {
return __syscall_umask_js(mask);
}
Loading