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

API DTO Implementation #18

Merged
merged 4 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading