Skip to content

Commit 3d78a7b

Browse files
committed
merge develop to main
2 parents dd83362 + 7b51af9 commit 3d78a7b

File tree

9 files changed

+389
-39
lines changed

9 files changed

+389
-39
lines changed

CONTRIBUTING.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@ All types of contributions are encouraged and valued.
1111
> - Mention the project at local meetups/conferences and tell your friends/colleagues
1212
> - Donate to cover the costs of maintaining it
1313
14-
1514
## I Have a Question
1615

17-
Do feel free to reach out to me at vignesh.vaidyanathan@hololinked.dev. I will try my very best to respond.
16+
Do feel free to reach out to me at vignesh.vaidyanathan@hololinked.dev or in discord. I will try my very best to respond.
1817

1918
Nevertheless, one may also refer the available how-to section of the [Documentation](https://hololinked.readthedocs.io/en/latest/index.html).
2019
If the documentation is insufficient for any reason including being poorly documented, one may open a new discussion in the [Q&A](https://github.com/VigneshVSV/hololinked/discussions/categories/q-a) section of GitHub discussions.
2120

2221
For questions related to workings of HTTP, JSON schema, basic concepts of python like descriptors, decorators etc., it is also advisable to search the internet for answers first.
23-
For generic questions related to web of things standards or its ideas, I recommend to join web of things [discord](https://discord.com/invite/RJNYJsEgnb) group and [community](https://www.w3.org/community/wot/) group.
22+
For generic questions related to web of things standards or its ideas, it is recommended to join web of things [discord](https://discord.com/invite/RJNYJsEgnb) group and [community](https://www.w3.org/community/wot/) group.
2423

2524
If you believe your question might also be a bug, you might want to search for existing [Issues](https://github.com/VigneshVSV/hololinked/issues) that might help you.
2625
In case you have found a suitable issue and still need clarification, you can write your question in this issue. If an issue is not found:
@@ -44,13 +43,21 @@ Otherwise, I will then take care of the issue as soon as possible.
4443
> ### Legal Notice <!-- omit in toc -->
4544
> When contributing to this project, you must agree that you have authored 100% of the content or that you have the necessary rights to the content. For example, you copied code from projects with MIT/BSD License. Content from GPL-related licenses may be maintained in a separate repository as an add-on.
4645
47-
Developers are always welcome to contribute to the code base. If you want to tackle any issues, un-existing features, let me know (at my email), I can create some open issues and features which I was never able to solve or did not have the time. You can also suggest what else can be contributed functionally or conceptually or also simply code-refactoring. The lack of issues or features in the [Issues](https://github.com/VigneshVSV/hololinked/issues) section of github does not mean the project is considered feature complete or I dont have ideas what to do next. On the contrary, there is tons of work to do.
46+
Developers are always welcome to contribute to the code base. If you want to tackle any issues, un-existing features, let me know (at my email), I can create some open issues and features which I was never able to solve or did not have the time. You can also suggest what else can be contributed functionally, conceptually or also simply code-refactoring.
4847

49-
There are also repositories which can use your skills:
48+
There are also other repositories which can use your skills:
5049
- An [admin client](https://github.com/VigneshVSV/thing-control-panel) in react
5150
- [Documentation](https://github.com/VigneshVSV/hololinked-docs) in sphinx which needs significant improvement in How-To's, beginner level docs which may teach people concepts of data acquisition or IoT, Docstring or API documentation of this repository itself
5251
- [Examples](https://github.com/VigneshVSV/hololinked-examples) in nodeJS, Dashboard/PyQt GUIs or server implementations using this package. Hardware implementations of unexisting examples are also welcome, I can open a directory where people can search for code based on hardware and just download your code.
5352

53+
## Git Branching
54+
55+
A simpler model is used roughly based on [this article](https://www.bitsnbites.eu/a-stable-mainline-branching-model-for-git/) -
56+
- main branch is where all stable developments are merged, all your branches must merge here
57+
- main branch is merged to release branch when it is decided to created a release.
58+
- A specific release is tagged and not created as its own branch. Instead release branch simply follows the main branch at the release time. People should clone the main branch for latest (mostly-) stable code base and release branch for released code base.
59+
- other branches are feature or bug fix branches. A develop branch may be used to make general improvements as the package is constantly evolving, but its not a specific philosophy to use a develop branch.
60+
- Bug fixes on releases must proceed from the tag of that release. Perhaps, even a new release can be made after fixing the bug by merging a bug fix branch to main branch.
5461

5562
## Attribution
5663
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!

hololinked/server/eventloop.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ async def execute_once(cls, instance_name : str, instance : Thing, instruction_s
353353
if action == "write":
354354
if resource.state is None or (hasattr(instance, 'state_machine') and
355355
instance.state_machine.current_state in resource.state):
356-
if isinstance(arguments, dict) and len(arguments) == 1 and "value" in arguments:
357-
return prop.__set__(owner_inst, arguments["value"])
356+
if isinstance(arguments, dict) and len(arguments) == 1 and 'value' in arguments:
357+
return prop.__set__(owner_inst, arguments['value'])
358358
return prop.__set__(owner_inst, arguments)
359359
else:
360360
raise StateMachineError("Thing {} is in `{}` state, however attribute can be written only in `{}` state".format(

hololinked/server/events.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def __get__(self, obj, objtype) -> "EventDispatcher":
6161

6262
def __get__(self, obj : ParameterizedMetaclass, objtype : typing.Optional[type] = None):
6363
try:
64+
if not obj:
65+
return self
6466
return obj.__dict__[self._internal_name]
6567
except KeyError:
6668
raise AttributeError("Event object not yet initialized, please dont access now." +

hololinked/server/state_machine.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from ..param.parameterized import Parameterized
77
from .utils import getattr_without_descriptor_read
8+
from .exceptions import StateMachineError
89
from .dataklasses import RemoteResourceInfoValidator
910
from .property import Property
1011
from .properties import ClassSelector, TypedDict, Boolean
@@ -107,7 +108,7 @@ def _prepare(self, owner : Parameterized) -> None:
107108
raise AttributeError(f"Object {resource} was not made remotely accessible," +
108109
" use state machine with properties and actions only.")
109110
else:
110-
raise AttributeError("Given state {} not in states Enum {}".format(state, self.states.__members__))
111+
raise StateMachineError("Given state {} not in states Enum {}".format(state, self.states.__members__))
111112

112113
# then the callbacks
113114
for state, objects in self.on_enter.items():

hololinked/server/td.py

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414

1515

16-
1716
@dataclass
1817
class Schema:
1918
"""
@@ -53,7 +52,9 @@ def format_doc(cls, doc : str):
5352
if index > 0:
5453
line = ' ' + line # add space to left in case of new line
5554
final_doc.append(line)
56-
return ''.join(final_doc)
55+
final_doc = ''.join(final_doc)
56+
final_doc = final_doc.lstrip().rstrip()
57+
return final_doc
5758

5859

5960

@@ -187,14 +188,14 @@ def build(self, property : Property, owner : Thing, authority : str) -> None:
187188
self.description = Schema.format_doc(property.doc)
188189
if property.metadata and property.metadata.get("unit", None) is not None:
189190
self.unit = property.metadata["unit"]
190-
# if property.allow_None:
191-
# if not hasattr(self, 'oneOf'):
192-
# self.oneOf = []
193-
# if hasattr(self, 'type'):
194-
# self.oneOf.append(dict(type=self.type))
195-
# del self.type
196-
# if not any(types["type"] == None for types in self.oneOf):
197-
# self.oneOf.append(dict(type=None))
191+
if property.allow_None:
192+
if not hasattr(self, 'oneOf'):
193+
self.oneOf = []
194+
if hasattr(self, 'type'):
195+
self.oneOf.append(dict(type=self.type))
196+
del self.type
197+
if not any(types["type"] == None for types in self.oneOf):
198+
self.oneOf.append(dict(type="null"))
198199

199200

200201

@@ -262,6 +263,17 @@ def generate_schema(self, property : Property, owner : Thing, authority : str) -
262263
schema = OneOfSchema()
263264
elif self._custom_schema_generators.get(property, NotImplemented) is not NotImplemented:
264265
schema = self._custom_schema_generators[property]()
266+
elif isinstance(property, Property) and property.model is not None:
267+
from .td_pydantic_extensions import GenerateJsonSchemaWithoutDefaultTitles, type_to_dataschema
268+
schema = PropertyAffordance()
269+
schema.build(property=property, owner=owner, authority=authority)
270+
data_schema = type_to_dataschema(property.model).model_dump(mode='json', exclude_none=True)
271+
final_schema = schema.asdict()
272+
if schema.oneOf: # allow_None = True
273+
final_schema['oneOf'].append(data_schema)
274+
else:
275+
final_schema.update(data_schema)
276+
return final_schema
265277
else:
266278
raise TypeError(f"WoT schema generator for this descriptor/property is not implemented. name {property.name} & type {type(property)}")
267279
schema.build(property=property, owner=owner, authority=authority)
@@ -719,17 +731,18 @@ class ThingDescription(Schema):
719731
'events', 'thing_description', 'GUI', 'object_info' ]
720732

721733
skip_actions = ['_set_properties', '_get_properties', '_add_property', '_get_properties_in_db',
722-
'push_events', 'stop_events', 'get_postman_collection', 'get_thing_description']
734+
'push_events', 'stop_events', 'get_postman_collection', 'get_thing_description',
735+
'get_our_temp_thing_description']
723736

724737
# not the best code and logic, but works for now
725738

726739
def __init__(self, instance : Thing, authority : typing.Optional[str] = None,
727-
allow_loose_schema : typing.Optional[bool] = False) -> None:
740+
allow_loose_schema : typing.Optional[bool] = False, ignore_errors : bool = False) -> None:
728741
super().__init__()
729742
self.instance = instance
730743
self.authority = authority
731744
self.allow_loose_schema = allow_loose_schema
732-
745+
self.ignore_errors = ignore_errors
733746

734747
def produce(self) -> typing.Dict[str, typing.Any]:
735748
self.context = "https://www.w3.org/2022/wot/td/v1.1"
@@ -754,26 +767,38 @@ def produce(self) -> typing.Dict[str, typing.Any]:
754767
def add_interaction_affordances(self):
755768
# properties and actions
756769
for resource in self.instance.instance_resources.values():
757-
if (resource.isproperty and resource.obj_name not in self.properties and
758-
resource.obj_name not in self.skip_properties and hasattr(resource.obj, "_remote_info") and
759-
resource.obj._remote_info is not None):
760-
if (resource.obj_name == 'state' and (not hasattr(self.instance, 'state_machine') or
761-
not isinstance(self.instance.state_machine, StateMachine))):
762-
continue
763-
self.properties[resource.obj_name] = PropertyAffordance.generate_schema(resource.obj,
770+
try:
771+
if (resource.isproperty and resource.obj_name not in self.properties and
772+
resource.obj_name not in self.skip_properties and hasattr(resource.obj, "_remote_info") and
773+
resource.obj._remote_info is not None):
774+
if (resource.obj_name == 'state' and (not hasattr(self.instance, 'state_machine') or
775+
not isinstance(self.instance.state_machine, StateMachine))):
776+
continue
777+
self.properties[resource.obj_name] = PropertyAffordance.generate_schema(resource.obj,
764778
self.instance, self.authority)
765-
elif (resource.isaction and resource.obj_name not in self.actions and
766-
resource.obj_name not in self.skip_actions and hasattr(resource.obj, '_remote_info')):
767-
self.actions[resource.obj_name] = ActionAffordance.generate_schema(resource.obj,
768-
self.instance, self.authority)
779+
780+
elif (resource.isaction and resource.obj_name not in self.actions and
781+
resource.obj_name not in self.skip_actions and hasattr(resource.obj, '_remote_info')):
782+
783+
self.actions[resource.obj_name] = ActionAffordance.generate_schema(resource.obj,
784+
self.instance, self.authority)
785+
except Exception as ex:
786+
if not self.ignore_errors:
787+
raise ex from None
788+
self.instance.logger.error(f"Error while generating schema for {resource.obj_name} - {ex}")
769789
# Events
770790
for name, resource in inspect._getmembers(self.instance, lambda o : isinstance(o, Event),
771791
getattr_without_descriptor_read):
772792
if not isinstance(resource, Event):
773793
continue
774794
if '/change-event' in resource.URL_path:
775795
continue
776-
self.events[name] = EventAffordance.generate_schema(resource, self.instance, self.authority)
796+
try:
797+
self.events[name] = EventAffordance.generate_schema(resource, self.instance, self.authority)
798+
except Exception as ex:
799+
if not self.ignore_errors:
800+
raise ex from None
801+
self.instance.logger.error(f"Error while generating schema for {resource.obj_name} - {ex}")
777802
# for name, resource in inspect._getmembers(self.instance, lambda o : isinstance(o, Thing), getattr_without_descriptor_read):
778803
# if resource is self.instance or isinstance(resource, EventLoop):
779804
# continue

0 commit comments

Comments
 (0)