Skip to content

Commit

Permalink
API DTO Implementation #18
Browse files Browse the repository at this point in the history
  • Loading branch information
haimkastner authored Apr 28, 2024
2 parents bf83a73 + a1add0b commit 82aee65
Show file tree
Hide file tree
Showing 132 changed files with 14,268 additions and 1,815 deletions.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ print(angle.to_string()) # 180 °

print(angle.to_string(AngleUnits.Degree)) # 180 °
print(angle.to_string(AngleUnits.Radian)) # 3.141592653589793 rad
```

## Additional methods

# Additional methods
Check, compare, calculate etc. with unitsnet:

```python
length1 = Length.from_meters(10)
length2 = Length.from_decimeters(100)
length3 = Length.from_meters(3)
Expand Down Expand Up @@ -99,6 +103,41 @@ print(np_array_double_length.kilometers) # [[ 4. 8. 12.][14. 16. 18.]]
print(np_array_double_length.meters) # [[ 4000. 8000. 12000.][14000. 16000. 18000.]]

```
## DTO - Data Transfer Object

As UnitsNet provides a convenient way to work within a running service, there are occasions where the data needs to be exposed outside of the service, typically through an API containing the unit value or consumed from an API.

To support this with a clear API schema and make it easy to convert to and from this schema to the specific format, it's recommended to use DTOs and the UnitsNet flavor converters.

```python
from unitsnet_py import Length, LengthDto, LengthUnits

# Create a Length unit object
length = Length.from_meters(100.01)
# Obtain the DTO object as json, represented by the default unit - meter
length_dto_json = length.to_dto_json() # {"value":100.01,"unit":"Meter"}
# Obtain the same value but represent DTO in KM
length_dto_represents_in_km_json = length.to_dto_json(LengthUnits.Kilometer) # {'value': 0.10001, 'unit': 'Kilometer'}
# Load JSON to DTO, and load
length_from_meters_dto = Length.from_dto_json(length_dto_json)
# The exact same value as
length_from_km_dto = Length.from_dto_json(length_dto_represents_in_km_json)

# Also, it supported to create and handle as DTO instance and to create to/from json to it.

# Get a DTO instance from a Length instance
length_dto: LengthDto = length.to_dto()
# Get the json representation of the DTO
length_json = length_dto.to_json() # {"value":100.01,"unit":"Meter"}
# Obtain DTO instance from a json representation
length_dto: LengthDto = LengthDto.from_json(length_json)
# Obtain Length unit from a DTO instance
length = Length.from_dto(length_dto)
```

Check out the OpenAPI [unitsnet-openapi-spec](https://haimkastner.github.io/unitsnet-openapi-spec-example/) example schema.

Also, refer to the detailed discussions on GitHub: [haimkastner/unitsnet-js#31](https://github.com/haimkastner/unitsnet-js/issues/31) & [angularsen/UnitsNet#1378](https://github.com/angularsen/UnitsNet/issues/1378).

### Supported units

Expand Down Expand Up @@ -487,4 +526,5 @@ Get the same strongly typed units on other platforms, based on the same [unit de
|----------------------------|-------------|---------------------------------------------------|------------------------------------------------------|--------------|
| C# | UnitsNet | [nuget](https://www.nuget.org/packages/UnitsNet/) | [github](https://github.com/angularsen/UnitsNet) | @angularsen |
| JavaScript /<br>TypeScript | unitsnet-js | [npm](https://www.npmjs.com/package/unitsnet-js) | [github](https://github.com/haimkastner/unitsnet-js) | @haimkastner |
| Python | unitsnet-py | [pypi](https://pypi.org/project/unitsnet-py) | [github](https://github.com/haimkastner/unitsnet-py) | @haimkastner |

121 changes: 121 additions & 0 deletions tests/test_unit_dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import unittest
from unitsnet_py import Length, LengthUnits, LengthDto

length1 = Length.from_meters(100.01)

class TestUnitDto(unittest.TestCase):
def test_create_json_from_default_unit(self):
self.assertDictEqual(length1.to_dto().to_json(), {
"value":100.01,
"unit":"Meter"
})


def test_create_json_from_specific_unit(self):
self.assertDictEqual(length1.to_dto(LengthUnits.Centimeter).to_json(), {
"value":10001,
"unit":"Centimeter"
})

def test_directly_create_json_from_unit(self):
self.assertDictEqual(length1.to_dto_json(), {
"value":100.01,
"unit":"Meter"
})

def test_directly_create_json_from_specific_unit(self):
self.assertDictEqual(length1.to_dto_json(LengthUnits.Centimeter), {
"value":10001,
"unit":"Centimeter"
})

def test_create_dto_from_default_unit(self):
dto = length1.to_dto()
self.assertEqual(dto.value, 100.01)
self.assertEqual(dto.unit, LengthUnits.Meter)


def test_create_dto_from_specific_unit(self):
dto = length1.to_dto(LengthUnits.Centimeter)
self.assertEqual(dto.value, 10001)
self.assertEqual(dto.unit, LengthUnits.Centimeter)


def test_load_from_default_unit_json(self):
json_dto = length1.to_dto().to_json()
new_length = Length.from_dto(LengthDto.from_json(json_dto))
self.assertEqual(new_length.meters, 100.01)


def test_load_from_specific_unit_json(self):
json_dto = length1.to_dto(LengthUnits.Centimeter).to_json()
new_length = Length.from_dto(LengthDto.from_json(json_dto))
self.assertEqual(new_length.decimeters, 1000.1)


def test_load_from_default_unit_dto(self):
dto = length1.to_dto()
new_length = Length.from_dto(dto)
self.assertEqual(new_length.meters, 100.01)


def test_load_from_specific_unit_dto(self):
dto = length1.to_dto(LengthUnits.Centimeter)
new_length = Length.from_dto(dto)
self.assertEqual(new_length.decimeters, 1000.1)

def test_load_from_json(self):
json = {
"value":100.01,
"unit":"Meter"
}
new_length = Length.from_dto(LengthDto.from_json(json))
self.assertEqual(new_length.meters, 100.01)

def test_load_directly_from_json(self):
json = {
"value":100.01,
"unit":"Meter"
}
new_length = Length.from_dto_json(json)
self.assertEqual(new_length.meters, 100.01)

def test_load_directly_from_specific_unit_json(self):
json = {
"value":10001,
"unit":"Centimeter"
}
new_length = Length.from_dto_json(json)
self.assertEqual(new_length.meters, 100.01)

def test_should_be_similar_values_from_two_dto_representations(self):
# Create a Length unit object
length = Length.from_meters(100.01)

# Obtain the DTO object as json, represented by the default unit - meter
length_dto_json = length.to_dto_json() # {"value":100.01,"unit":"Meter"}

# Obtain the same value but represent DTO in KM
length_dto_represents_in_km_json = length.to_dto_json(LengthUnits.Kilometer) # {'value': 0.10001, 'unit': 'Kilometer'}

# Load JSON to DTO, and load
length_from_meters_dto = Length.from_dto_json(length_dto_json)
# The exact same value as
length_from_km_dto = Length.from_dto_json(length_dto_represents_in_km_json)

self.assertEqual(length_from_meters_dto.meters, length_from_km_dto.meters)

# Get a DTO instance from a Length instance
length_dto: LengthDto = length.to_dto()
# Get the json representation of the DTO
length_json = length_dto.to_json() # {"value":100.01,"unit":"Meter"}
# Obtain DTO instance from a json representation
length_dto: LengthDto = LengthDto.from_json(length_json)
# Obtain Length unit from a DTO instance
length = Length.from_dto(length_dto)

self.assertEqual(length.meters, length_from_meters_dto.meters)


if __name__ == "__main__":
unittest.main()
21 changes: 11 additions & 10 deletions units_generator/common/fetch_units_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,27 @@ def get_definitions(repo_owner_and_name):
definition = get_json_from_cdn(f"{files_url}/{name}")

for unit in definition["Units"]:
markAsDeprecated = False
pluralName = unit.get("PluralName")
obsoleteText = unit.get("ObsoleteText")
if obsoleteText:
mark_as_deprecated = False
unit_name = unit.get("Name")
plural_name = unit.get("PluralName")
obsolete_text = unit.get("ObsoleteText")
if obsolete_text:
print(
f'[get_definitions] Unit {name}.{pluralName} marked as obsolete, message: "{obsoleteText}"'
f'[get_definitions] Unit {unit_name}.{plural_name} marked as obsolete, message: "{obsolete_text}"'
)
markAsDeprecated = True
mark_as_deprecated = True

if unit.get("SkipConversionGeneration"):
print(
f"[get_definitions] Unit {name}.{pluralName} marked to be ignored"
f"[get_definitions] Unit {unit_name}.{plural_name} marked to be ignored"
)
markAsDeprecated = True
mark_as_deprecated = True

unit["Deprecated"] = markAsDeprecated
unit["Deprecated"] = mark_as_deprecated

definitions.append(definition)

print(f"[get_definitions] Unit {name}.{pluralName} successfully fetched")
print(f"[get_definitions] Unit {name} successfully fetched")

print("[get_definitions] Fetching units definitions finished successfully")

Expand Down
1 change: 1 addition & 0 deletions units_generator/generators/generate_unit_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def unit_class_generator(unit_definition):

template_data = {
"unit": unit_name,
"unit_camel_case": camel_to_snake(unit_name),
"base_unit": unit_definition.get("BaseUnit"),
"description": unit_definition.get("XmlDocSummary"),
"methods": template_methods,
Expand Down
4 changes: 2 additions & 2 deletions units_generator/templates/export_template.jinja2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% for method in methods %}from .units.{{ method.unit }} import {{ method.unit_name }}, {{ method.unit_name }}Units
{% for method in methods %}from .units.{{ method.unit }} import {{ method.unit_name }}, {{ method.unit_name }}Units, {{ method.unit_name }}Dto
{% endfor %}

__all__ = [
{% for method in methods %} '{{ method.unit_name }}', '{{ method.unit_name }}Units',
{% for method in methods %} '{{ method.unit_name }}', '{{ method.unit_name }}Units', '{{ method.unit_name }}Dto',
{% endfor %}]
42 changes: 41 additions & 1 deletion units_generator/templates/readme_template.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ print(angle.to_string()) # 180 °

print(angle.to_string(AngleUnits.Degree)) # 180 °
print(angle.to_string(AngleUnits.Radian)) # 3.141592653589793 rad
```

## Additional methods

# Additional methods
Check, compare, calculate etc. with unitsnet:

```python
length1 = Length.from_meters(10)
length2 = Length.from_decimeters(100)
length3 = Length.from_meters(3)
Expand Down Expand Up @@ -99,6 +103,41 @@ print(np_array_double_length.kilometers) # [[ 4. 8. 12.][14. 16. 18.]]
print(np_array_double_length.meters) # [[ 4000. 8000. 12000.][14000. 16000. 18000.]]

```
## DTO - Data Transfer Object

As UnitsNet provides a convenient way to work within a running service, there are occasions where the data needs to be exposed outside of the service, typically through an API containing the unit value or consumed from an API.

To support this with a clear API schema and make it easy to convert to and from this schema to the specific format, it's recommended to use DTOs and the UnitsNet flavor converters.

```python
from unitsnet_py import Length, LengthDto, LengthUnits

# Create a Length unit object
length = Length.from_meters(100.01)
# Obtain the DTO object as json, represented by the default unit - meter
length_dto_json = length.to_dto_json() # {"value":100.01,"unit":"Meter"}
# Obtain the same value but represent DTO in KM
length_dto_represents_in_km_json = length.to_dto_json(LengthUnits.Kilometer) # {'value': 0.10001, 'unit': 'Kilometer'}
# Load JSON to DTO, and load
length_from_meters_dto = Length.from_dto_json(length_dto_json)
# The exact same value as
length_from_km_dto = Length.from_dto_json(length_dto_represents_in_km_json)

# Also, it supported to create and handle as DTO instance and to create to/from json to it.

# Get a DTO instance from a Length instance
length_dto: LengthDto = length.to_dto()
# Get the json representation of the DTO
length_json = length_dto.to_json() # {"value":100.01,"unit":"Meter"}
# Obtain DTO instance from a json representation
length_dto: LengthDto = LengthDto.from_json(length_json)
# Obtain Length unit from a DTO instance
length = Length.from_dto(length_dto)
```

Check out the OpenAPI [unitsnet-openapi-spec](https://haimkastner.github.io/unitsnet-openapi-spec-example/) example schema.

Also, refer to the detailed discussions on GitHub: [haimkastner/unitsnet-js#31](https://github.com/haimkastner/unitsnet-js/issues/31) & [angularsen/UnitsNet#1378](https://github.com/angularsen/UnitsNet/issues/1378).

### Supported units

Expand All @@ -118,5 +157,6 @@ Get the same strongly typed units on other platforms, based on the same [unit de
|----------------------------|-------------|---------------------------------------------------|------------------------------------------------------|--------------|
| C# | UnitsNet | [nuget](https://www.nuget.org/packages/UnitsNet/) | [github](https://github.com/angularsen/UnitsNet) | @angularsen |
| JavaScript /<br>TypeScript | unitsnet-js | [npm](https://www.npmjs.com/package/unitsnet-js) | [github](https://github.com/haimkastner/unitsnet-js) | @haimkastner |
| Python | unitsnet-py | [pypi](https://pypi.org/project/unitsnet-py) | [github](https://github.com/haimkastner/unitsnet-py) | @haimkastner |


Loading

0 comments on commit 82aee65

Please sign in to comment.