Skip to content
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

number type should no longer differentiate between integer and decima… #6800

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelogs/unreleased/6526-index-float-int.yml
@@ -0,0 +1,9 @@
description: number type should no longer differentiate between integer and decimal notation when used in indexes.
issue-nr: 6526
issue-repo: inmanta-core
change-type: minor
destination-branches: [iso6]
sections:
feature: "Introduce the 'float' type for floating point numbers"
deprecation-note: "Deprecate the 'number' type. Use the 'int' or 'float' type instead"

16 changes: 11 additions & 5 deletions docs/language.rst
Expand Up @@ -125,14 +125,18 @@ Literal values can be assigned to variables
Primitive types
==============================

The basic primitive types are ``string``, ``number``, ``int`` or ``bool``. These basic types also support type casts:
The basic primitive types are ``string``, ``float``, ``int`` or ``bool``. These basic types also support type casts:

.. note::
To initialize or assign a float, the value should either include a decimal point or be explicitly converted to a float type.


.. code-block:: inmanta

assert = true
assert = int("1") == 1
assert = number("1.2") == 1.2
assert = number(true) == 1
assert = float("1.2") == 1.2
assert = int(true) == 1
assert = bool(1.2) == true
assert = bool(0) == false
assert = bool(null) == false
Expand Down Expand Up @@ -164,7 +168,7 @@ For example
typedef mac_addr as string matching /([0-9a-fA-F]{2})(:[0-9a-fA-F]{2}){5}$/


Lists of primitive types are also primitive types: ``string[]``, ``number[]``, ``bool[]`` or ``mac_addr[]``
Lists of primitive types are also primitive types: ``string[]``, ``float[]``, ``bool[]`` or ``mac_addr[]``

``dict`` is the primitive type that represents a dictionary, with string keys. Dict values can be accessed using the ``[]`` operator. All members of a dict have to be set when the dict is constructed. e.g.

Expand Down Expand Up @@ -690,13 +694,15 @@ For indices on relations (instead of attributes) an alternative syntax can be us
# a == b

.. note::
The use of ``number`` as part of index properties is
The use of ``float`` (or ``number``) as part of index properties is
generally discouraged. This is due to the reliance of index matching on precise equality,
while floating-point numbers are represented with an inherent imprecision.
If floating-point attributes are used in an index, it is crucial to handle arithmetic
operations with caution to ensure the accuracy of the attribute values for index operations.




For loop
=========

Expand Down
7 changes: 7 additions & 0 deletions src/inmanta/ast/__init__.py
Expand Up @@ -21,6 +21,7 @@
from functools import lru_cache
from typing import Dict, List, Optional, Union

from inmanta import warnings
from inmanta.ast import export
from inmanta.stable_api import stable_api
from inmanta.warnings import InmantaWarning
Expand All @@ -41,6 +42,10 @@
from inmanta.plugins import PluginException


class TypeDeprecationWarning(InmantaWarning):
pass


class Location(export.Exportable):
__slots__ = ("file", "lnr")

Expand Down Expand Up @@ -382,6 +387,8 @@ def get_type(self, typ: LocatableString) -> "Type":
else:
raise TypeNotFoundException(typ, self)
elif name in self.primitives:
if name == "number":
warnings.warn(TypeDeprecationWarning("Type 'number' is deprecated, use 'float' or 'int' instead"))
return self.primitives[name]
else:
cns = self # type: Optional[Namespace]
Expand Down
16 changes: 12 additions & 4 deletions src/inmanta/ast/entity.py
Expand Up @@ -33,7 +33,7 @@
)
from inmanta.ast.blocks import BasicBlock
from inmanta.ast.statements.generator import SubConstructor
from inmanta.ast.type import NamedType, Type
from inmanta.ast.type import Float, NamedType, Type
from inmanta.execute.runtime import Instance, QueueScheduler, Resolver, dataflow
from inmanta.execute.util import AnyType

Expand Down Expand Up @@ -382,6 +382,7 @@ def add_to_index(self, instance: Instance) -> None:
been set
"""
attributes = {k: repr(v.get_value()) for (k, v) in instance.slots.items() if v.is_ready()}

# check if an index entry can be added
for index_attributes in self.get_indices():
index_ok = True
Expand Down Expand Up @@ -427,9 +428,16 @@ def lookup_index(
raise NotFoundException(
stmt, self.get_full_name(), "No index defined on %s for this lookup: " % self.get_full_name() + str(params)
)

key = ", ".join(["%s=%s" % (k, repr(v)) for (k, v) in sorted(params, key=lambda x: x[0])])

key = ", ".join(
[
"%s=%s"
% (
k,
repr(self.get_attribute(k).type.cast(v) if isinstance(self.get_attribute(k).type, Float) else v),
)
for k, v in sorted(params, key=lambda x: x[0])
]
)
if target is None:
if key in self._index:
return self._index[key]
Expand Down
55 changes: 49 additions & 6 deletions src/inmanta/ast/type.py
Expand Up @@ -229,7 +229,7 @@ def __eq__(self, other: object) -> bool:
@stable_api
class Number(Primitive):
"""
This class represents an integer or float in the configuration model.
This class represents an integer or a float in the configuration model.
"""

def __init__(self) -> None:
Expand All @@ -254,7 +254,7 @@ def validate(self, value: Optional[object]) -> bool:
return True

if not isinstance(value, numbers.Number):
raise RuntimeException(None, "Invalid value '%s', expected Number" % value)
raise RuntimeException(None, "Invalid value '%s', expected %s" % (value, self.type_string()))

return True # allow this function to be called from a lambda function

Expand All @@ -271,6 +271,42 @@ def type_string_internal(self) -> str:
return self.type_string()


@stable_api
class Float(Primitive):
"""
This class is an alias for the Number class and represents a float in
the configuration model.
"""

def __init__(self) -> None:
Primitive.__init__(self)
self.try_cast_functions: Sequence[Callable[[Optional[object]], object]] = [float]

def validate(self, value: Optional[object]) -> bool:
"""
Validate the given value to check if it satisfies the constraints
associated with this type
"""
if isinstance(value, AnyType):
return True

if not isinstance(value, float):
raise RuntimeException(None, "Invalid value '%s', expected %s" % (value, self.type_string()))
return True # allow this function to be called from a lambda function

def is_primitive(self) -> bool:
return True

def get_location(self) -> None:
return None

def type_string(self) -> str:
return "float"

def type_string_internal(self) -> str:
return self.type_string()


@stable_api
class Integer(Number):
"""
Expand All @@ -282,11 +318,17 @@ def __init__(self) -> None:
self.try_cast_functions: Sequence[Callable[[Optional[object]], object]] = [int]

def validate(self, value: Optional[object]) -> bool:
if not super().validate(value):
return False
"""
Validate the given value to check if it satisfies the constraints
associated with this type
"""
if isinstance(value, AnyType):
return True

if not isinstance(value, numbers.Integral):
raise RuntimeException(None, "Invalid value '%s', expected %s" % (value, self.type_string()))
return True

return True # allow this function to be called from a lambda function

def type_string(self) -> str:
return "int"
Expand Down Expand Up @@ -590,7 +632,7 @@ class Literal(Union):
"""

def __init__(self) -> None:
Union.__init__(self, [NullableType(Number()), Bool(), String(), TypedList(self), TypedDict(self)])
Union.__init__(self, [NullableType(Float()), Number(), Bool(), String(), TypedList(self), TypedDict(self)])

def type_string_internal(self) -> str:
return "Literal"
Expand Down Expand Up @@ -694,6 +736,7 @@ def function(*args, **kwargs):

TYPES: typing.Dict[str, Type] = { # Part of the stable API
"string": String(),
"float": Float(),
"number": Number(),
"int": Integer(),
"bool": Bool(),
Expand Down
8 changes: 4 additions & 4 deletions tests/compiler/dataflow/test_model_assignment.py
Expand Up @@ -104,7 +104,7 @@ def test_dataflow_model_attribute_assignment_responsible(dataflow_test_helper: D
dataflow_test_helper.compile(
"""
entity Test:
number n
int n
end
implement Test using std::none

Expand Down Expand Up @@ -204,7 +204,7 @@ def test_dataflow_model_assignment_from_attribute(dataflow_test_helper: Dataflow
dataflow_test_helper.compile(
"""
entity A:
number n
int n
end
implement A using std::none

Expand Down Expand Up @@ -232,7 +232,7 @@ def test_dataflow_model_assignment_outside_constructor(dataflow_test_helper: Dat
dataflow_test_helper.compile(
"""
entity A:
number n
int n
end
implement A using std::none

Expand Down Expand Up @@ -268,7 +268,7 @@ def test_dataflow_model_result_variable(dataflow_test_helper: DataflowTestHelper
dataflow_test_helper.compile(
"""
entity A:
number n
int n
end

index A(n)
Expand Down
10 changes: 5 additions & 5 deletions tests/compiler/dataflow/test_model_datatrace.py
Expand Up @@ -142,7 +142,7 @@
"equivalence with attribute",
"""
entity A:
number n
int n
end
implement A using std::none

Expand Down Expand Up @@ -192,11 +192,11 @@
"implementation",
"""
entity A:
number n
int n
end

entity B:
number n
int n
end

implementation ia for A:
Expand Down Expand Up @@ -260,8 +260,8 @@
"index match double assignment",
"""
entity A:
number n
number m
int n
int m
end

index A(n)
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/dataflow/test_model_dynamic_scope.py
Expand Up @@ -31,11 +31,11 @@ def test_dataflow_model_implementation_assignment_from_self(dataflow_test_helper
dataflow_test_helper.compile(
"""
entity A:
number n
int n
end

entity B:
number n
int n
end

A.b [1] -- B
Expand Down
14 changes: 7 additions & 7 deletions tests/compiler/dataflow/test_model_graphic.py
Expand Up @@ -193,9 +193,9 @@ def test_dataflow_graphic_instance(graphic_asserter: GraphicAsserter) -> None:
graphic_asserter(
"""
entity A:
number l
number m
number n
int l
int m
int n
end

implement A using std::none
Expand Down Expand Up @@ -329,8 +329,8 @@ def test_dataflow_graphic_implementation(graphic_asserter: GraphicAsserter) -> N
graphic_asserter(
"""
entity A:
number m
number n
int m
int n
end

implement A using i
Expand Down Expand Up @@ -393,8 +393,8 @@ def test_dataflow_graphic_index(graphic_asserter: GraphicAsserter) -> None:
graphic_asserter(
"""
entity A:
number m
number n
int m
int n
end

index A(n)
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/dataflow/test_model_index.py
Expand Up @@ -29,8 +29,8 @@ def test_dataflow_model_index_resultvariable_binding(dataflow_test_helper: Dataf
dataflow_test_helper.compile(
"""
entity A:
number n
number m
int n
int m
end

index A(n)
Expand Down