-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[CT-2848] [Bug] dbt show
adding decimal places to non-decimal values
#8153
Comments
dbt show
adding decimal places to non-decimal valuesdbt show
adding decimal places to non-decimal values
did some more local testing on other versions of 1.5 and observed the same behavior - -this may not be a regression, but just a regular bug! |
dbt show
adding decimal places to non-decimal valuesdbt show
adding decimal places to non-decimal values
Copying from #8167 (great minds think alike @dave-connors-3): What's going on?We're just using the dbt-core/core/dbt/task/show.py Lines 78 to 83 in eeb0570
This is being returned and saved as a ipdb> table
<agate.table.Table object at 0x1078d1360>
ipdb> [list(row) for row in table]
[['0005', 'false', Decimal('10'), False, '01T00000aabbccdd'], ['0006', 'true', Decimal('20'), True, '01T00000aabbccde']]
ipdb> table.print_json()
[{"stringnum": "0005", "stringbool": "false", "intfield": 10.0, "boolfield": false, "dtstring": "01T00000aabbccdd"}, {"stringnum": "0006", "stringbool": "true", "intfield": 20.0, "boolfield": true, "dtstring": "01T00000aabbccde"}]
ipdb> type(table[0][2])
<class 'decimal.Decimal'> |
Thanks to 2 great minds for opening this up! It does look like this was an issue with prior versions of the IDE (before the That being said, we definitely want to enable users to be able to spot check their data using |
Experiencing the same issue here, running dbt version 1.5.0. Following for updates. |
I think we might be able to fix this with a couple of additional overrides in our custom class Number(agate.data_types.Number):
# undo the change in https://github.com/wireservice/agate/pull/733
# i.e. do not cast True and False to numeric 1 and 0
def cast(self, d):
if type(d) == bool:
raise agate.exceptions.CastError("Do not cast True to 1 or False to 0.")
# preserve integers as native Python int
elif type(d) == int:
return d
else:
return super().cast(d)
def jsonify(self, d):
if d is None:
return d
# do not cast integers to floats
elif type(d) == int:
return d
return float(d)
|
@dave-connors-3 Okay, the failing CI in #8306 reminded me of what was missing with my suggestion above. While this fixes the JSON output, it now raises an error while trying to do normal pretty-printed output, because Approach 1: During JSON serialization, if it can be an int, make it an intIn this approach, we allow the Only during JSON serialization, we convert all numbers with 0-scale (no digits after the decimal) to integers instead of floats. (Unfortunately, the Downside: This would remove the distinction between integer and decimal/numeric type, in the case where someone is saying class Number(agate.data_types.Number):
# undo the change in https://github.com/wireservice/agate/pull/733
# i.e. do not cast True and False to numeric 1 and 0
def cast(self, d) -> Decimal:
if type(d) == bool:
raise agate.exceptions.CastError("Do not cast True to 1 or False to 0.")
else:
return super().cast(d)
def jsonify(self, d) -> Union[int, float]:
if d is None:
return d
# do not cast integers to floats
elif d == int(d):
# fancier way of doing the same: "if agate.utils.max_precision([d]) == 0|
return int(d)
else:
return float(d)
It still works for decimals that have nonzero digits after the decimal place, but we're dropping any trailing zeroes. (Remember "significant digits"? Remember high-school science class?)
Approach 2: Integer != NumberRather than changing the # we do not want integers being coerced to decimals in JSON output
class Integer(agate.data_types.DataType):
def cast(self, d) -> int:
if type(d) == int:
return d
else:
raise CastError('Can not parse value "%s" as Integer.' % d)
def jsonify(self, d) -> int:
return d
class Number(agate.data_types.Number):
# undo the change in https://github.com/wireservice/agate/pull/733
# i.e. do not cast True and False to numeric 1 and 0
def cast(self, d) -> decimal.Decimal:
if type(d) == bool:
raise agate.exceptions.CastError("Do not cast True to 1 or False to 0.")
else:
return super().cast(d) Then, within our type tester further down, we need to try casting to def build_type_tester(
text_columns: Iterable[str], string_null_values: Optional[Iterable[str]] = ("null", "")
) -> agate.TypeTester:
types = [
Integer(null_values=("null", "")),
Number(null_values=("null", "")),
... Because This does preserve the distinction between integers and decimals/numerics, although it doesn't preserve the exact scale of the original result set: $ psql
psql (14.8 (Homebrew), server 13.11)
Type "help" for help.
jerco=# select
cast(1 as numeric(38,3)) as _numeric,
cast(1 as integer) as _integer,
cast(1 as decimal(38,2)) as _decimal
;
_numeric | _integer | _decimal
----------+----------+----------
1.000 | 1 | 1.00
(1 row)
On its face, this feels like the More Correct approach. HOWEVER!! There is a risk of a very subtle breaking change here. Because we expose agate types to end users, in the form of
We've never explicitly documented that you can do those things, but it would be a subtle breaking change nevertheless. We don't encounter this issue with Approach 1, because the values remain |
@jtcohen6 it seems like option 2 is better here, with us documenting the breaking part of the change and only backporting to 1.6. Does that seem reasonable? |
Yup, that's what I'm thinking too! |
Re-opening - we had to revert this fix due to a number of failing tests and an error when running |
when running with the associated change in the IDE, i executed a
This error seems to stem from the |
Is this a regression in a recent version of dbt-core?
Current Behavior
dbt show
is adding decimal places to numeric/integer values incorrectly. This is causing problems for users in the dbt Cloud IDE, as the IDE uses that command to render the preview tab.Expected/Previous Behavior
Previously (we think!) this was not an issue, and decimal places were properly handled by dbt show
Steps To Reproduce
dbt show -s my_model --output JSON
Relevant log output
No response
Environment
Which database adapter are you using with dbt?
snowflake
Additional Context
No response
The text was updated successfully, but these errors were encountered: