GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

GH-42018: [Python] Add NumPy StringDType to Arrow conversion - #51157

Open
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype
Open

GH-42018: [Python] Add NumPy StringDType to Arrow conversion#51157
ngoldbaum wants to merge 7 commits into
apache:mainfrom
ngoldbaum:from-numpy-stringdtype

Conversation

@ngoldbaum

Copy link
Copy Markdown

Rationale for this change

NumPy 2.0 added StringDType, a variable-width UTF-8 string dtype. pa.array currently rejects it with Unsupported numpy type 2056. Now that pyarrow requires NumPy 2.0 the conversion can use the public NpyString_* C API.

This supersedes #50951. The first commit is @alippai's first commit from that PR, unchanged. His later commits added batching and new bulk builder APIs in Arrow C++; those can come later in their own PR with benchmarks, as discussed there. Nothing outside the NumPy conversion code changes here.

What changes are included in this PR?

  • NumPyDtypeToArrow maps StringDType to string, so it is also the inferred type for pa.array, pa.infer_type, pa.from_numpy_dtype and lists of such arrays. large_string and string_view can be requested with type. Any other type raises a TypeError naming the requested type.
  • The conversion holds the dtype's allocator lock for the whole array and never holds the GIL while taking it.
  • A null entry in a StringDType array becomes an Arrow null unless the dtype's na_object is a str. NumPy reports such entries as that string from __getitem__, in ufuncs and comparisons, and in casts, and there is no way to tell them apart from a regular entry holding the same string, so the conversion writes the string too. NaN-like sentinels such as np.nan and pd.NA, None, and arbitrary objects all become arrow nulls.
  • A short section in docs/source/python/numpy.rst describing the support and the semantics for converting missing data.

If left unfixed, #51156 also becomes possible to trigger from Python by creating a StringDType array with a very large entry.

Are these changes tested?

Yes. Tests cover the three target types, strings crossing NumPy's short, medium and long storage thresholds, non-ASCII input, strided input, mask, None, NaN and string sentinels, the rejected target type, and list inference. I also ran a threaded test that converts an array while other threads hit NumPy's null-comparison error path on the same array to check the lock ordering.

Are there any user-facing changes?

Yes. pa.array and the inference functions accept StringDType arrays.

AI disclosure: I used an AI model to work on the follow-up commits on top of @alippai's first commit and for code review.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ngoldbaum@alippai