Skip to content

Commit

Permalink
Merge branch 'master' into 164-Adding-multientity-to-tutorials
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
#	setup.py
  • Loading branch information
djs0109 committed Apr 24, 2024
2 parents b173b53 + 5e46ea4 commit 23f8dad
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 89 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
### v0.4.1
- fix: Session added as optional parameter to enable tls communication with clients ([#249](https://github.com/RWTH-EBC/FiLiP/pull/249))
### v0.4.2
- add: validation for JEXL based expression ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))
- add: tutorials for multi-entity ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))

### v0.4.1
- fix: Session added as optional parameter to enable tls communication with clients ([#249](https://github.com/RWTH-EBC/FiLiP/pull/249))
- fix: add missing package ``geojson_pydantic`` in setup.py ([#276](https://github.com/RWTH-EBC/FiLiP/pull/276))
- add: support entity creation with keyvalues ([#264](https://github.com/RWTH-EBC/FiLiP/pull/264))

#### v0.4.0
- add tutorial for protected endpoint with bearer authentication ([#208](https://github.com/RWTH-EBC/FiLiP/issues/208))
- add internal mqtt url for unittests @djs0109 ([#239](https://github.com/RWTH-EBC/FiLiP/pull/239))
Expand Down
60 changes: 32 additions & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
# Contribute as a user

The documentation, examples and tutorials should be understandable and the code bug-free.
As all user's have different backgrounds, you may not understand everything or encounter bugs.
In that case, PLEASE raise an issue [here](https://github. com/RWTH-EBC/filip/issues/new).
As all users have different backgrounds, you may not understand everything or encounter bugs.
In that case, PLEASE raise an issue [here](https://github.com/RWTH-EBC/filip/issues/new).

Consider labeling the issue using the flag `bug` or `documentation` / `question`.
Consider labeling the issue with an [appropriate label](https://github.com/RWTH-EBC/FiLiP/labels).

# Contribute as a developer

If you instead want to contribute new features or fix bugs yourself, we are more than happy.

Please also [raise an issue](https://github.com/RWTH-EBC/filip/issues/new)
create a new branch labeled `XY_some_name`.
Here, `XY` is the number of your issue and `some_name` is a meaningful
description.
Alternatively and preferred, issue branches are created automatically on issue
assignment with [robvanderleek/create-issue-branch](https://github.com/robvanderleek/create-issue-branch).
Please [raise an issue](https://github.com/RWTH-EBC/filip/issues/new).
Issue branches are created automatically on issue assignments.

See [workflow definition](.github/workflows/issue-tracker.yml) and
[configuration file](.github/issue-branch.yml) for customization.

Branch creation is skipped for issues with label "question".
Branch creation is skipped for issues with the label "question".

Once you're feature is ready, create a pull request and check if the pipeline succeeds.
Once your feature is ready, create a pull request and check if the pipeline succeeds.
Assign a reviewer before merging.
Once review is finished, you can merge.

**Before** implementing or modifying modules, classes or functions, please read the following page.

## Styleguide
## Style guides

We use PEP8 as a styleguide. Some IDEs (like PyCharm) automatically show you code that is not in PEP8. If you don't have such an IDE, please read [this page](https://pep8.org/) to get a better understanding of it.
### Coding style guide

We use PEP8 as a coding style guide. Some IDEs (like PyCharm) automatically show you code that is not in PEP8. If you don't have such an IDE, please read [this page](https://pep8.org/) to get a better understanding of it.

### Committing style guide

For committing style guide please use Conventional Commits 1.0.0. For more details how to structure your commits please visit this [page](https://www.conventionalcommits.org/en/v1.0.0/).

## Documentation

All created or modified function should be documented properly.
All created or modified functions should be documented properly.
Try to follow the structure already present.
If possible, write a little doctest example into the docstring to make clear to user's what the desired output of your function is.
If possible, write a little doctest example into the docstring to make clear to the user what the desired output of your function is.
All non-self-explanatory lines of code should include a comment.
Although you will notice that not all docstring are already in this style we use the google-style for docstrings, e.g.
Although you will notice that not all docstring are already in this style, we use the google-style for docstrings, e.g.

```python

Expand All @@ -57,23 +59,25 @@ def foo(dummy: str , dummy2: Union[str, int]):

Furthermore, we use type annotations as this helps users to automatically
identify wrong usage of functions.
In a further step type annotations may also help to accelerate your code.
For further details please check the official [documentation on type hints](https://docs.python.org/3/library/typing.html).
In a further step, type annotations may also help to accelerate your code.
For more details please check the official [documentation on type hints](https://docs.python.org/3/library/typing.html).

## Unit-Tests
Espacially when creating new functions or classes, you have to add a unit-test function.
Open the `test_module.py` file in the `\tests`-directory and add a function to the class `TestModule`with a name like `test_my_new_function`. If you create a new module, you have to create a new `test_my_new_module.py` file and follow the existing structure of the
other test-files.
Especially when creating new functions or classes, you have to add a unit-test function.
Tests are located in the `\tests` directory. Every file that includes tests has a `test_` prefix.
Open the appropriate module where you want to write a test and add an appropriate function.
When you are adding tests to an existing test file, it is also recommended that you study the other tests in that file; it will teach you which precautions you have to take to make your tests robust and portable.
If the corresponding module does not exist, then you should create a new module with `test_` prefix and appropriate name.

If you are not familiar with unit-tests, here is a quick summary:
- Test as many things as possible. Even seemingly silly tests like correct input-format help prevent future problems for new users
- use the `self.assertSOMETHING` functions provided by `unittest`. This way a test failure is presented correctly An error inside your test function will not be handeled as a failure but an error.
- If the success of your test depends on the used device, you can use decorators like `skip()`, `skipif(numpy.__version__<(1, 0), "not supported with your numpy version")`, etc.
- `setUp()` and `tearDown()` are called before and after each test. Use this functions to define parameters used in every test, or to close applications like Dymola once a test is completed.
- See the [unittest-documentation](https://docs.python.org/3/library/unittest.html#organizing-tests) for further information
- Test as many things as possible. Even seemingly silly tests like correct input-format help prevent future problems for new users.
- Use the `self.assertSOMETHING` functions provided by `unittest`. This way a test failure is presented correctly. An error inside your test function will not be handled as a failure but as an error.
- If the success of your test depends on the used development environment, you can use decorators like `skip()`, `skipif(numpy.__version__<(1, 0), "not supported with your numpy version")`, etc.
- `setUp()` and `tearDown()` are called before and after each test. Use these functions to define parameters used in every test, or to close applications like Dymola once a test is completed.
- See the [unittest-documentation](https://docs.python.org/3/library/unittest.html#organizing-tests) for further information.

You can check your work by running all tests before commiting to git.
You can check your work by running all tests before committing to git.

## Pylint
With pylint we try to keep our code clean.
See the description in [this repo](https://git.rwth-aachen.de/EBC/EBC_all/gitlab_ci/templates/tree/master/pylint) on information on what pylint is and how to use it.
[Here](https://pypi.org/project/pylint/) you can read more about Pylint and how to use it.
3 changes: 2 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ The following topics are covered:

#### How to use ontologies for semantic system modelling?

- [semantics](https://github.com/RWTH-EBC/FiLiP/tree/master/examples/ngsi_v2/e11_ngsi_v2_semantics)
- [Semantics](https://github.com/RWTH-EBC/FiLiP/tree/master/examples/ngsi_v2/e11_ngsi_v2_semantics)
- [Use-case specific data modeling](https://github.com/RWTH-EBC/FiLiP/tree/master/examples/ngsi_v2/e12_ngsi_v2_use_case_models.py)

156 changes: 156 additions & 0 deletions examples/ngsi_v2/e12_ngsi_v2_use_case_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
"""
# This example shows a workflow, how you can define or reuse use case specific data
# models and ensure FIWARE compatibility by merging these models with existing data
# model in FiLiP. The merged models can be used for interaction with FIWARE platform
# and in other information processing systems to establish interoperability.
# In short: this workflow shows you a way to keep use case model simple and
# reusable while ensuring the compatability with FIWARE NGSI-V2 standards
"""
from pydantic import ConfigDict, BaseModel
from pydantic.fields import Field, FieldInfo
from filip.models import FiwareHeader
from filip.models.ngsi_v2.context import ContextEntityKeyValues
from filip.clients.ngsi_v2.cb import ContextBrokerClient
from filip.utils.cleanup import clear_context_broker
from pprint import pprint

# Host address of Context Broker
CB_URL = "http://localhost:1026"

# You can here also change the used Fiware service
# FIWARE-Service
SERVICE = 'filip'
# FIWARE-Servicepath
SERVICE_PATH = '/'
fiware_header = FiwareHeader(service=SERVICE,
service_path=SERVICE_PATH)


# Reuse existing data model from the internet
class PostalAddress(BaseModel):
"""
https://schema.org/PostalAddress
"""

model_config = ConfigDict(populate_by_name=True, coerce_numbers_to_str=True)

address_country: str = Field(
alias="addressCountry",
description="County code according to ISO 3166-1-alpha-2",
)
street_address: str = Field(
alias="streetAddress",
description="The street address. For example, 1600 Amphitheatre Pkwy.",
)
address_region: str = Field(
alias="addressRegion",
default=None,
)
address_locality: str = Field(
alias="addressLocality",
default=None,
description="The locality in which the street address is, and which is "
"in the region. For example, Mountain View.",
)
postal_code: str = Field(
alias="postalCode",
default=None,
description="The postal code. For example, 94043.",
)


# It is assumed that this kind of models exists in use case, which is simple and use case
# specific. It describes basically, how does the data look like in the specific use case.
class WeatherStation(BaseModel):
model_config = ConfigDict(coerce_numbers_to_str=True, extra="ignore")
temperature: float = Field(default=20.0)
humidity: float = Field(default=50.0)
pressure: float = Field(default=1.0)
address: PostalAddress


# Merge the use case model with the FIWARE simplified data model to ensure FIWARE
# compatibility.
class WeatherStationFIWARE(WeatherStation, ContextEntityKeyValues):
# add default for type if not explicitly set
type: str = FieldInfo.merge_field_infos(
# First position is the field info of the parent class
ContextEntityKeyValues.model_fields["type"],
# set the default value
default="CustomModels:WeatherStation",
# overwrite the title in the json-schema if necessary
title="Type of the Weather Station",
# overwrite the description
description="Type of the Weather Station",
# validate the default value if necessary
validate_default=True,
# freeze the field if necessary
frozen=True,
# for more options see the pydantic documentation
)


if __name__ == "__main__":
# Now we can export both the use case model and the FIWARE specific
# models to json-schema files and share it with other stakeholders
# or applications/services that need to use the data.
use_case_model = WeatherStation.model_json_schema()
pprint(use_case_model)

fiware_specific_model = WeatherStationFIWARE.model_json_schema()
pprint(fiware_specific_model)

# Workflow to utilize these data models.

# 0. Initial client
cb_client = ContextBrokerClient(url=CB_URL,
fiware_header=fiware_header)
# clear cb
clear_context_broker(cb_client=cb_client)

# 1. Crate data
weather_station = WeatherStationFIWARE(
id="myWeatherStation",
type="WeatherStation",
temperature=20,
address={
"address_country": "Germany",
"street_address": "Mathieustr. 10",
"postal_code": 52072,
},
)
cb_client.post_entity(entity=weather_station, key_values=True,
update=True)

# 2. Update data
weather_station.temperature = 30 # represent use case algorithm
cb_client.update_entity_key_values(entity=weather_station)

# 3. Query and validate data
# represent querying data by data users
weather_station_data = cb_client.get_entity(entity_id="myWeatherStation",
response_format="keyValues")
# validate with general model
weather_station_2_general = WeatherStation.model_validate(
weather_station_data.model_dump()
)
# validate with fiware specific model
weather_station_2_fiware = WeatherStationFIWARE.model_validate(
weather_station_data.model_dump()
)

# 4. Use data for different purposes
# for use case specific usage
print("Data complied with general model can be forwarded to other platform/system:\n"
f"{weather_station_2_general.model_dump_json(indent=2)}")
print(f"For example, address still comply with existing model:\n"
f"{weather_station_2_general.address.model_dump_json(indent=2)}\n")

# for fiware specific usage
print("For usage within FIWARE system, id and type is helpful, e.g. for creating"
"notification for entity:\n"
f"{weather_station_2_fiware.model_dump_json(indent=2, include={'id', 'type'})}\n")

# clear cb
clear_context_broker(cb_client=cb_client)
2 changes: 1 addition & 1 deletion filip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from filip.config import settings
from filip.clients.ngsi_v2 import HttpClient

__version__ = '0.4.0'
__version__ = '0.4.1'
Loading

0 comments on commit 23f8dad

Please sign in to comment.