-
-
Notifications
You must be signed in to change notification settings - Fork 714
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
Units do not allow ° symbol #6495
Comments
Thanks for the fast response and fix! Unfortunately, this fix does not work for me. I used the following steps to update the code:
The console output of invoke update stated multiple pint redefinitions, such as: Sadly, it still doesn't work for me. Perhaps my work flow for updating the code is wrong? I also don't quite understand why this would work, as °C is already defined by pint: Btw, not wanting to be a nitpicker, but Kelvin does not use the ° symbol anymore. Don't ask me why, but pint uses °K as well, although it is wrong: The line reg.define('degreeK = °K = degK = kelvin = Kelvin') in your fix should actually be reg.define('degreeK = K = degK = kelvin = Kelvin') |
Ok, I can reproduce this... And now am very deep in the weeds. For future reference: |
I think the problem with °C and similar units is, that pint does not store these representations as an alias but rather as a symbol. I made a pretty ugly fix to support temperature units below. I highlighted the code changes with comments (FIX TEMPERATURE UNIT 1/2). Use with caution though, as I have not tested it properly. File: InvenTree/InvenTree/conversion.py def convert_physical_value(value: str, unit: str = None, strip_units=True):
original = str(value).strip()
# Ensure that the value is a string
value = str(value).strip() if value else ''
unit = str(unit).strip() if unit else ''
# Error on blank values
if not value:
raise ValidationError(_('No value provided'))
if unit:
backup_value = value + unit
else:
backup_value = None
ureg = get_unit_registry()
# FIX TEMPERATURE UNITS BEGIN 1
try:
temperature_args = is_temperature(value)
if temperature_args:
value = ureg.Quantity(*temperature_args)
value = value.to(unit)
else:
value = ureg.Quantity(value)
if unit:
if is_dimensionless(value):
magnitude = value.to_base_units().magnitude
value = ureg.Quantity(magnitude, unit)
else:
value = value.to(unit)
# FIX TEMPERATURE UNITS END 1
except Exception:
if backup_value:
try:
value = ureg.Quantity(backup_value)
except Exception:
value = None
else:
value = None
if value is None:
if unit:
raise ValidationError(_(f'Could not convert {original} to {unit}'))
else:
raise ValidationError(_("Invalid quantity supplied"))
# Calculate the "magnitude" of the value, as a float
# If the value is specified strangely (e.g. as a fraction or a dozen), this can cause issues
# So, we ensure that it is converted to a floating point value
# If we wish to return a "raw" value, some trickery is required
try:
if unit:
magnitude = ureg.Quantity(value.to(ureg.Unit(unit))).magnitude
else:
magnitude = ureg.Quantity(value.to_base_units()).magnitude
magnitude = float(ureg.Quantity(magnitude).to_base_units().magnitude)
except Exception as exc:
raise ValidationError(_(f'Invalid quantity supplied ({exc})'))
if strip_units:
return magnitude
elif unit or value.units:
return ureg.Quantity(magnitude, unit or value.units)
return ureg.Quantity(magnitude)
# FIX TEMPERATURE UNITS BEGIN 2
def convert_to_number(value):
try:
return int(value)
except ValueError:
try:
return float(value)
except ValueError:
return value
def is_temperature(value):
try:
ureg = get_unit_registry()
for unit in ureg.get_compatible_units('[temperature]'):
# do not change order of if clauses!
if str(unit) in value:
return (convert_to_number(value.replace(str(unit), "")), unit)
for alias in list(ureg._units[str(unit)].aliases):
if alias in value:
return (convert_to_number(value.replace(alias, "")), unit)
if ureg._units[str(unit)].symbol in value:
return (convert_to_number(value.replace(ureg._units[str(unit)].symbol, "")), unit)
return False
except:
return False
# FIX TEMPERATURE UNITS END 2 |
Logarithmic units will fail as well. For these units to work, the unit registry needs to be initialized with the autoconvert_offset_to_baseunit flag set to True |
@fohrt I had found the autoconvert_offset_to_baseunit - not sure if it would have any unforeseen consequences to other conversion? Setting this parameter seems to make temperature units just work. So it is a simple fix for sure. Any idea about other effects it might have? |
This is what the documentation of pint says about it:
For the given use case, I think both behaviors will be fine. The first behavior seems to be just what we want. The second behavior should not be much of a problem because the conversion to the unit supplied in the parameter template is called explicitly at the end. So only intermediate results will be represented in the base unit. One thing to note is that this will also enable support for logarithmic units (beta feature of pint). |
Yes that seems pretty reasonable. Do you think you would be able to submit a PR to implement this? In addition to the registry init update (single line of code) we should add some unit tests to ensure that a variety of temperature conversions are handled correctly: InvenTree/InvenTree/InvenTree/tests.py Line 43 in 7adf2e0
|
I encountered a similar issue. When I input a unit with a Chinese character, the system reported an error. If I used an English letter or string, it worked. My system was migrated from the older version which doesn't have this issue before; the new version 0.13.5 reported an error for old data. after I defined the physical unit in the global setting - physical unit (Chinese character to English unit "piece"), the issue was solved. |
@weizhangny locale issues would be separate to the temperature symbol issue here - I would suggest you make a new issue for that. It would be a good idea to look into whether the pint library offers multi lingual support, as a starting point. |
Please verify that this bug has NOT been raised before.
Describe the bug*
I want to add temperatures as parameters, but whenever I add a unit that features the ° symbol in the name, I get an error.
This would not be a problem if the actual unit symbol was shown instead of the unit name because the unit symbol does allow the ° symbol.
Steps to Reproduce
Enforce Parameter Units has to be set to true for the errors to occur:
Alternatively, a similar error can be reproduced by the following steps:
Expected behaviour
No error should occur when defining a unit with the ° symbol.
Not the unit name, but the unit symbol should be displayed.
Deployment Method
Version Information
Version Information:
InvenTree-Version: 0.13.3
Django Version: 3.2.23
Commit Hash: e81349e
Commit Date: None
Commit Branch: stable
Database: sqlite3
Debug-Mode: False
Deployed using Docker: False
Platform: Linux-5.15.0-94-generic-x86_64-with-glibc2.31
Installer: PKG
Target: ubuntu:20.04
Active plugins: [{'name': 'InvenTreeBarcode', 'slug': 'inventreebarcode', 'version': '2.0.0'}, {'name': 'InvenTreeCoreNotificationsPlugin', 'slug': 'inventreecorenotificationsplugin', 'version': '1.0.0'}, {'name': 'InvenTreeCurrencyExchange', 'slug': 'inventreecurrencyexchange', 'version': '1.0.0'}, {'name': 'InvenTreeLabel', 'slug': 'inventreelabel', 'version': '1.0.0'}, {'name': 'InvenTreeLabelSheet', 'slug': 'inventreelabelsheet', 'version': '1.0.0'}, {'name': 'DigiKeyPlugin', 'slug': 'digikeyplugin', 'version': '1.0.0'}, {'name': 'LCSCPlugin', 'slug': 'lcscplugin', 'version': '1.0.0'}, {'name': 'MouserPlugin', 'slug': 'mouserplugin', 'version': '1.0.0'}, {'name': 'TMEPlugin', 'slug': 'tmeplugin', 'version': '1.0.0'}]
Please verify if you can reproduce this bug on the demo site.
Relevant log output
No response
The text was updated successfully, but these errors were encountered: