diff --git a/src/tasker/actions/__init__.py b/src/tasker/actions/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/tasker/profiles/__init__.py b/src/tasker/profiles/__init__.py
new file mode 100644
index 0000000..f2ef86a
--- /dev/null
+++ b/src/tasker/profiles/__init__.py
@@ -0,0 +1 @@
+from .time import Time
diff --git a/src/tasker/profiles/time.py b/src/tasker/profiles/time.py
new file mode 100644
index 0000000..0f97b5c
--- /dev/null
+++ b/src/tasker/profiles/time.py
@@ -0,0 +1,27 @@
+from dataclasses import dataclass
+
+from tasker.py import Event
+
+
+@dataclass
+class Time(Event):
+ start_hour: int
+ start_minute: int
+
+ end_hour: int
+ end_minute: int
+
+ _every_type = None
+ _every_value = None
+
+ def every_hour(self, value: int):
+ self._every_type = 1
+ self._every_value = value
+
+ return self
+
+ def every_minute(self, value: int):
+ self._every_type = 2
+ self._every_value = value
+
+ return self
diff --git a/src/tasker/py/__init__.py b/src/tasker/py/__init__.py
index f99b239..56cec77 100644
--- a/src/tasker/py/__init__.py
+++ b/src/tasker/py/__init__.py
@@ -1,4 +1,5 @@
from .action import Action
+from .event import Event
from .main import TaskerPy
from .profile import Profile
from .profile_variable import ProfileVariable
diff --git a/src/tasker/py/event.py b/src/tasker/py/event.py
new file mode 100644
index 0000000..046c171
--- /dev/null
+++ b/src/tasker/py/event.py
@@ -0,0 +1,7 @@
+from dataclasses import dataclass
+
+@dataclass
+class Event:
+ """Basic building block for new profiles"""
+
+ _code_ = 0
diff --git a/src/tasker/py/main.py b/src/tasker/py/main.py
index 4e759b9..f9fbe02 100644
--- a/src/tasker/py/main.py
+++ b/src/tasker/py/main.py
@@ -10,6 +10,8 @@
from .scene import Scene
from .task import Task
+from .event import Event
+
@dataclass
class TaskerPy:
@@ -61,11 +63,36 @@ def _generate_id(self, name: str) -> int:
hash_md5 = md5(name.encode()).hexdigest()
return int(hash_md5[:7], 16)
+ def add_profile(
+ self,
+ name: str,
+ event: Event,
+ profile_id: int = None
+ ):
+ def decorator(task: Task):
+ profile = Profile(
+ profile_id,
+ task.id,
+ name,
+ event
+ )
+
+ if profile.id is None:
+ profile.id = self._generate_id(name)
+
+ if not (0 < profile.id < 1_000_000_000):
+ raise ValueError('Profile id invalid min: 0 max: 999_999_999')
+
+ self._profiles.append(profile)
+ return profile
+
+ return decorator
+
def add_task(
self,
- name: str | None = None,
- task_id: int | None = None,
- output_variables: dict[str, str] | None = None,
+ name: str = None,
+ task_id: int = None,
+ output_variables: dict[str, str] = None,
):
"""
Decorator to add a task to the TaskerPy application.
diff --git a/src/tasker/py/profile.py b/src/tasker/py/profile.py
index 45639de..21536a2 100644
--- a/src/tasker/py/profile.py
+++ b/src/tasker/py/profile.py
@@ -1,7 +1,9 @@
from dataclasses import dataclass
-
+from .event import Event
@dataclass
class Profile:
id: int
task_id: int
+ name: str
+ event: Event
diff --git a/src/tasker/xml/profile_xml.py b/src/tasker/xml/profile_xml.py
index 19b3133..50a17dc 100644
--- a/src/tasker/xml/profile_xml.py
+++ b/src/tasker/xml/profile_xml.py
@@ -1,6 +1,64 @@
from .xml_builder import XmlBuilder
+from tasker.py.profile import Profile
+from tasker.profiles import Time
+
class ProfileXml(XmlBuilder):
- def __init__(self, profile):
+ def __init__(self, profile: Profile):
self.profile = profile
+
+ def _create_event(self):
+ E = self.E
+
+ profile_event = self.profile.event
+
+ match profile_event:
+ case Time():
+ start_hour = str(profile_event.start_hour)
+ start_minute = str(profile_event.start_minute)
+
+ end_hour = str(profile_event.end_hour)
+ end_minute = str(profile_event.end_minute)
+
+ every_type = profile_event._every_type
+
+ every_list = []
+
+ if (every_type is not None):
+ every_type = str(every_type)
+ every_value = str(
+ profile_event._every_value
+ )
+
+ every_list = [
+ E.rep(every_type),
+ E.repval(every_value)
+ ]
+
+ yield E.Time(
+ E.fh(start_hour),
+ E.fm(start_minute),
+ *every_list,
+ E.th(end_hour),
+ E.tm(end_minute),
+ sr='con0'
+ )
+
+ def to_xml(self):
+ E = self.E
+
+ profile_id = str(self.profile.id)
+ task_id = str(self.profile.task_id)
+ profile_name = self.profile.name
+
+ return E.Profile(
+ E.cdate('0'),
+ E.edate('1'),
+ E.flags('8'),
+ E.id(profile_id),
+ E.mid0(task_id),
+ E.nme(profile_name),
+ *self._create_event(),
+ sr='prof'
+ )
diff --git a/src/tasker/xml/task_xml.py b/src/tasker/xml/task_xml.py
index ceea85e..6b4c213 100644
--- a/src/tasker/xml/task_xml.py
+++ b/src/tasker/xml/task_xml.py
@@ -85,7 +85,11 @@ def _profile_variables_to_xml(self, *variables: ProfileVariable):
def to_xml(self):
E = self.E
- task_collision = int(self.task.collision)
+ task_id = str(self.task.id)
+ task_name = self.task.name
+ task_priority = str(self.task.priority)
+ task_collision = str(self.task.collision)
+
notify = str(self.task.notify).lower()
awake = str(self.task.awake).lower()
profile_variables = self.task.profile_variables
@@ -98,10 +102,10 @@ def to_xml(self):
return E.Task(
E.cdate('0'),
E.edate('1'),
- E.id(f'{self.task.id}'),
- E.nme(self.task.name),
- E.pri(f'{self.task.priority}'),
- E.rty(f'{task_collision}'),
+ E.id(task_id),
+ E.nme(task_name),
+ E.pri(task_priority),
+ E.rty(task_collision),
E.showinnot(notify),
E.stayawake(awake),
*self._actions_to_xml(*self.task()),
diff --git a/test/__mocks__/profiles/time.xml b/test/__mocks__/profiles/time.xml
new file mode 100644
index 0000000..26396f3
--- /dev/null
+++ b/test/__mocks__/profiles/time.xml
@@ -0,0 +1,36 @@
+
+
+ 0
+ 1
+ 8
+ 1
+ 172601898
+ Profile Time
+
+
+
+ 0
+ 1
+ 172601898
+ task_beep
+ 100
+ 0
+ false
+ false
+
+ 171
+
+
+
+
+
+
+
+
diff --git a/test/__mocks__/beep.xml b/test/__mocks__/tasks/beep.xml
similarity index 93%
rename from test/__mocks__/beep.xml
rename to test/__mocks__/tasks/beep.xml
index b40f7f4..4a0532d 100644
--- a/test/__mocks__/beep.xml
+++ b/test/__mocks__/tasks/beep.xml
@@ -14,7 +14,7 @@
-
+
diff --git a/test/__mocks__/flash.xml b/test/__mocks__/tasks/flash.xml
similarity index 67%
rename from test/__mocks__/flash.xml
rename to test/__mocks__/tasks/flash.xml
index 56a80c5..1b4dc20 100644
--- a/test/__mocks__/flash.xml
+++ b/test/__mocks__/tasks/flash.xml
@@ -13,19 +13,19 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
+
-
+
diff --git a/test/__mocks__/flash_profile_variables.xml b/test/__mocks__/tasks/flash_profile_variables.xml
similarity index 100%
rename from test/__mocks__/flash_profile_variables.xml
rename to test/__mocks__/tasks/flash_profile_variables.xml
diff --git a/test/conftest.py b/test/conftest.py
index be5977c..05ae3bb 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -2,8 +2,9 @@
from pytest import Function, fixture, mark
-from tasker.actions.alert import Beep, Flash
-from tasker.py import TaskerPy
+from tasker.actions.alert import Beep, Flash, Notify
+from tasker.profiles.time import Time
+from tasker.py import TaskerPy, Profile
@fixture
@@ -40,3 +41,15 @@ def task_flash():
yield Flash('Hello, World')
return task_flash
+
+@fixture
+def time_profile(beep_task):
+ app = TaskerPy()
+
+ profile_creator = app.add_profile(
+ 'Profile Time',
+ Time(12, 0, 20, 0).every_hour(2),
+ profile_id=1,
+ )
+
+ return profile_creator(beep_task)
diff --git a/test/helpers/str_exporter.py b/test/helpers/str_exporter.py
new file mode 100644
index 0000000..a9d4831
--- /dev/null
+++ b/test/helpers/str_exporter.py
@@ -0,0 +1,11 @@
+from pathlib import Path
+
+
+PYCACHE_DIR = 'test/__pycache__/'
+
+path_default = Path(PYCACHE_DIR)
+
+
+def tmp_export_str(filename: str, data: str):
+ path = path_default / filename
+ path.write_text(data, encoding='utf8')
diff --git a/test/helpers/xml_reader.py b/test/helpers/xml_reader.py
new file mode 100644
index 0000000..8003af5
--- /dev/null
+++ b/test/helpers/xml_reader.py
@@ -0,0 +1,36 @@
+from lxml import etree
+from pathlib import Path
+
+
+MOCK_DIR = 'test/__mocks__'
+
+path_default = Path(MOCK_DIR)
+
+
+def xml_to_string(element_xml):
+ return etree.tostring(element_xml, pretty_print=True, encoding='utf-8').decode()
+
+
+def read_file(path: Path):
+ return path.read_text(encoding='utf8')
+
+
+def read_xml_task(filename):
+ path = path_default / 'tasks'
+ path /= filename
+
+ return read_file(path)
+
+
+def read_xml_profile(filename):
+ path = path_default / 'profiles'
+ path /= filename
+
+ return read_file(path)
+
+
+def read_xml_scene(filename):
+ path = path_default / 'scenes'
+ path /= filename
+
+ return read_file(path)
diff --git a/test/test_profile_xml.py b/test/test_profile_xml.py
new file mode 100644
index 0000000..65f7b8e
--- /dev/null
+++ b/test/test_profile_xml.py
@@ -0,0 +1,23 @@
+from tasker.xml import TaskerXml
+
+from test.helpers.xml_reader import (
+ read_xml_profile,
+ xml_to_string
+)
+
+from test.helpers.str_exporter import tmp_export_str
+
+
+def test_time_xml(time_profile, beep_task):
+ expected_xml = read_xml_profile('time.xml')
+
+ xml = TaskerXml(
+ profiles=[time_profile],
+ tasks=[beep_task],
+ ).to_xml()
+
+ xml_string = xml_to_string(xml)
+
+ tmp_export_str('time_exported.xml', xml_string)
+
+ assert xml_string == expected_xml
diff --git a/test/test_task_xml.py b/test/test_task_xml.py
index 74ff755..f50d329 100644
--- a/test/test_task_xml.py
+++ b/test/test_task_xml.py
@@ -1,23 +1,18 @@
-from lxml import etree
from pytest import fixture
from tasker.py.profile_variable import ProfileVariable
from tasker.xml import TaskerXml
+from test.helpers.xml_reader import (
+ read_xml_task,
+ xml_to_string
+)
-def xml_to_string(element_xml):
- etree.tostring(element_xml, pretty_print=True, encoding='utf-8').decode()
-
-
-def read_xml(path):
- parser = etree.XMLParser(remove_blank_text=True)
- mock_tree = etree.parse(path, parser)
-
- return xml_to_string(mock_tree)
+from test.helpers.str_exporter import tmp_export_str
def test_beep_xml(beep_task):
- expected_xml = read_xml('test/__mocks__/beep.xml')
+ expected_xml = read_xml_task('beep.xml')
task_xml = TaskerXml(tasks=[beep_task]).to_xml()
xml_string = xml_to_string(task_xml)
@@ -25,7 +20,7 @@ def test_beep_xml(beep_task):
def test_flash_xml(flash_task):
- expected_xml = read_xml('test/__mocks__/flash.xml')
+ expected_xml = read_xml_task('flash.xml')
task_xml = TaskerXml(tasks=[flash_task]).to_xml()
xml_string = xml_to_string(task_xml)
@@ -33,7 +28,7 @@ def test_flash_xml(flash_task):
def test_task_profile_variable(flash_task):
- expected_xml = read_xml('test/__mocks__/flash_profile_variables.xml')
+ expected_xml = read_xml_task('flash_profile_variables.xml')
flash_task.profile_variables = [
ProfileVariable(variable_name='%test_variable', value='TEST_VALUE'),
@@ -53,4 +48,7 @@ def test_task_profile_variable(flash_task):
task_xml = TaskerXml(tasks=[flash_task]).to_xml()
xml_string = xml_to_string(task_xml)
+
+ tmp_export_str('task_profile_exported.xml', xml_string)
+
assert xml_string == expected_xml