Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 4.3k
ARROW-2145/ARROW-2153/ARROW-2157/ARROW-2160/ARROW-2177: [Python] Decimal conversion not working for NaN values#1651
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
8e816ecf5623788893a450665f6ee6ac86450e35d68be22a67c7270a77a41ee4c74c63d905202281f7981df6923db664f2092a962418754fb24ff253190b1aa05b3164e6db3c29e1ebcb4bcfd978cbf5103ee999ae5db5f99505a900be578ab3e4a50d456881fc2a9697fcb96File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #!/usr/bin/env bash | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
| if [ "$ARROW_CI_C_GLIB_AFFECTED" = "1" ]; then | ||
| brew update | ||
| brew bundle --file=$TRAVIS_BUILD_DIR/c_glib/Brewfile | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -76,7 +76,15 @@ class ScalarVisitor { | ||
| timestamp_count_(0), | ||
| float_count_(0), | ||
| binary_count_(0), | ||
| unicode_count_(0) {} | ||
| unicode_count_(0), | ||
| decimal_count_(0), | ||
| max_decimal_metadata_(std::numeric_limits<int32_t>::min(), | ||
| std::numeric_limits<int32_t>::min()), | ||
| decimal_type_() { | ||
| PyAcquireGIL lock; | ||
| Status status = internal::ImportDecimalType(&decimal_type_); | ||
| DCHECK_OK(status); | ||
| } | ||
| Status Visit(PyObject* obj) { | ||
| ++total_count_; | ||
| @@ -111,10 +119,13 @@ class ScalarVisitor { | ||
| ss << type->ToString(); | ||
| return Status::Invalid(ss.str()); | ||
| } | ||
| } else if (PyObject_IsInstance(obj, decimal_type_.obj())) { | ||
| RETURN_NOT_OK(max_decimal_metadata_.Update(obj)); | ||
| ++decimal_count_; | ||
| } else { | ||
| // TODO(wesm): accumulate error information somewhere | ||
| static std::string supported_types = | ||
| "bool, float, integer, date, datetime, bytes, unicode"; | ||
| "bool, float, integer, date, datetime, bytes, unicode, decimal"; | ||
| std::stringstream ss; | ||
| ss << "Error inferring Arrow data type for collection of Python objects. "; | ||
| RETURN_NOT_OK(InvalidConversion(obj, supported_types, &ss)); | ||
| @@ -125,7 +136,9 @@ class ScalarVisitor { | ||
| std::shared_ptr<DataType> GetType() { | ||
| // TODO(wesm): handling mixed-type cases | ||
| if (float_count_) { | ||
| if (decimal_count_) { | ||
| return decimal(max_decimal_metadata_.precision(), max_decimal_metadata_.scale()); | ||
| } else if (float_count_) { | ||
| return float64(); | ||
| } else if (int_count_) { | ||
| // TODO(wesm): tighter type later | ||
| @@ -157,8 +170,13 @@ class ScalarVisitor { | ||
| int64_t float_count_; | ||
| int64_t binary_count_; | ||
| int64_t unicode_count_; | ||
| int64_t decimal_count_; | ||
| internal::DecimalMetadata max_decimal_metadata_; | ||
| // Place to accumulate errors | ||
| // std::vector<Status> errors_; | ||
| OwnedRefNoGIL decimal_type_; | ||
| }; | ||
| static constexpr int MAX_NESTING_LEVELS = 32; | ||
| @@ -379,17 +397,14 @@ class TypedConverter : public SeqConverter { | ||
| BuilderType* typed_builder_; | ||
| }; | ||
| // We use the CRTP trick here to devirtualize the AppendItem()and AppendNull() | ||
| // We use the CRTP trick here to devirtualize the AppendItem(), AppendNull(), and IsNull() | ||
| // method calls. | ||
| template <typename BuilderType, class Derived> | ||
| class TypedConverterVisitor : public TypedConverter<BuilderType> { | ||
| public: | ||
| Status AppendSingle(PyObject* obj) override { | ||
| if (obj == Py_None) { | ||
| return static_cast<Derived*>(this)->AppendNull(); | ||
| } else { | ||
| return static_cast<Derived*>(this)->AppendItem(obj); | ||
| } | ||
| auto self = static_cast<Derived*>(this); | ||
| return self->IsNull(obj) ? self->AppendNull() : self->AppendItem(obj); | ||
| } | ||
| Status AppendMultiple(PyObject* obj, int64_t size) override { | ||
| @@ -409,6 +424,7 @@ class TypedConverterVisitor : public TypedConverter<BuilderType> { | ||
| // Append a missing item (default implementation) | ||
| Status AppendNull() { return this->typed_builder_->AppendNull(); } | ||
| bool IsNull(PyObject* obj) const { return obj == Py_None; } | ||
| }; | ||
| class NullConverter : public TypedConverterVisitor<NullBuilder, NullConverter> { | ||
| @@ -830,12 +846,16 @@ class DecimalConverter | ||
| public: | ||
| // Append a non-missing item | ||
| Status AppendItem(PyObject* obj) { | ||
| /// TODO(phillipc): Check for nan? | ||
| Decimal128 value; | ||
| const auto& type = static_cast<const DecimalType&>(*typed_builder_->type()); | ||
| RETURN_NOT_OK(internal::DecimalFromPythonDecimal(obj, type, &value)); | ||
| return typed_builder_->Append(value); | ||
| } | ||
| bool IsNull(PyObject* obj) const { | ||
| return obj == Py_None || obj == numpy_nan || internal::PyFloat_isnan(obj) || | ||
| (internal::PyDecimal_Check(obj) && internal::PyDecimal_ISNAN(obj)); | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ugh, Python, what did we do to deserve this? =) | ||
| } | ||
| }; | ||
| // Dynamic constructor for sequence converters | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the rationale for this, the symbol linking issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import pyarrow.parquetwas segfaulting, I assumed because we're statically linking boost in the parquet build and dynamically in the arrow build. This only shows up when using the regex library.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, we should be consistent about which we do across the libraries. Part of why I wish we were building all these libraries in a monorepo setting