List of commits:
Subject Hash Author Date (UTC)
Implement child/parent system for Items d386115411ba0397b08d75b298d7843bddb477d9 Detche 2017-10-19 22:46:28
Initial commit 14d016d7ec773a17c3d72fc8352f6c683825e040 Detche 2017-10-19 20:44:14
Commit d386115411ba0397b08d75b298d7843bddb477d9 - Implement child/parent system for Items
Author: Detche
Author date (UTC): 2017-10-19 22:46
Committer name: Detche
Committer date (UTC): 2017-10-19 22:46
Parent(s): 14d016d7ec773a17c3d72fc8352f6c683825e040
Signing key:
Tree: 2aa16f6fe52e00b6950dbc9c3166240d66124462
File Lines added Lines deleted
helpgen/category.py 2 30
helpgen/document.py 5 0
helpgen/item.py 49 18
helpgen/project.py 9 0
helpgen/utils.py 38 0
File helpgen/category.py changed (mode: 100644) (index 3046570..2275901)
1 1 #!/usr/bin/env python #!/usr/bin/env python
2 2 """ A category corresponds to a Item with no content, simply children. """ """ A category corresponds to a Item with no content, simply children. """
3 3
4 import os
5 import sys
6
7 4 from item import Item from item import Item
8 5
9 6 class Category(Item): class Category(Item):
10 def __init__(self, path=None):
11 if path is not None:
12 if not os.path.exists(path):
13 raise FileNotFoundError('category path not found.', path)
14 assert os.path.isdir(path), 'non-dir given to Category constructor.'
15
16 # Open our metadata file. It should be named category.yaml/yml
17 metapath = os.path.join(path, 'category.yml')
18 if not os.path.exists(metapath):
19 metapath = os.path.join(path, 'category.yaml')
20 if not os.path.exists(metapath):
21 raise FileNotFoundError('Category metadata file not found.',
22 metapath)
23 super(Category, self).__init__(metapath)
24
25 def can_have_children(self):
26 """ Category children are expected to be Categories or Documents. """
27 return True
28
29 if __name__ == '__main__':
30 args = sys.argv[1:]
31 if len(args) == 0:
32 print("expected directory path")
33 exit()
34
35 cat = Category(args[0])
36 print(cat.name())
7 metafile = 'category.yml'
8 can_child = ['Document', 'Category']
37 9
File helpgen/document.py changed (mode: 100644) (index 7ad69c7..bfd916b)
1 1 #!/usr/bin/env python #!/usr/bin/env python
2 2 """ Represents a document part that can be included in the final document.""" """ Represents a document part that can be included in the final document."""
3 3
4 from item import Item
5
6 class Document(Item):
7 metafile = 'document.yml'
8 can_child = None
4 9
File helpgen/item.py changed (mode: 100644) (index 6d4b4da..0b0baac)
... ... import os
9 9 import yaml import yaml
10 10
11 11 class Item: class Item:
12 def __init__(self, path=None):
12 metafile = None
13 can_child = None
14
15 def __init__(self, path=None, name=None):
13 16 """ Initializes the Item by parsing the Yaml file, if provided.""" """ Initializes the Item by parsing the Yaml file, if provided."""
14 17 self.path = '' self.path = ''
15 18 self.metadata = None self.metadata = None
16 19 self.parent = None self.parent = None
17 20 self.children = [] self.children = []
18 21
19 if path is not None:
22 if name is not None:
23 assert len(name), 'cannot give empty name to item.'
24 self.metadata = {}
25 self.metadata['name'] = name
26 elif path is not None:
20 27 assert len(path), 'Empty path given to Item constructor.' assert len(path), 'Empty path given to Item constructor.'
21 28 if not os.path.exists(path): if not os.path.exists(path):
22 29 raise FileNotFoundError('path to meta document is invalid.', raise FileNotFoundError('path to meta document is invalid.',
23 30 path) path)
31 # If path is a directory, we guess the path to the metafile
32 # base on the static class variable that defines it.
33 if os.path.isdir(path):
34 assert self.metafile is not None, 'not metafile set for item.'
35 path = os.path.join(path, self.metafile)
36 if not os.path.exists(path):
37 raise FileNotFoundError('metafile does not exist.', path)
24 38 with open(path) as f: with open(path) as f:
25 39 self.metadata = yaml.safe_load(f) self.metadata = yaml.safe_load(f)
26 40 self.path = path self.path = path
27 41
28 def can_have_children(self):
29 """ Whether or not this item can have children. """
30 return False
42 def __str__(self):
43 return self.name() + ' (' + type(self).__name__ + ')'
31 44
32 45 def _get_value(self, name, lang=''): def _get_value(self, name, lang=''):
33 46 """ Get the value designated by name or its translation. """ Get the value designated by name or its translation.
 
... ... class Item:
72 85
73 86 def is_included_in(self, editions): def is_included_in(self, editions):
74 87 """ Whether the item should be included in the given edition(s). """ """ Whether the item should be included in the given edition(s). """
75 if self.metadata is None return False
76 if 'editions' not in self.metadata return True
88 if self.metadata is None:
89 return False
90 if 'editions' not in self.metadata:
91 return True
77 92 if isinstance(editions, str): if isinstance(editions, str):
78 if editions in self.metadata.editions return True
93 if editions in self.metadata['editions']:
94 return True
79 95 return False return False
80 96 if isinstance(editions, list): if isinstance(editions, list):
81 97 for edition in editions: for edition in editions:
82 if edition in self.metadata.editions return True
98 if edition in self.metadata['editions']:
99 return True
83 100 return False return False
84 101
85 def set_parent(self, parent):
86 """ Set the parent of this Item. Called by add_child(). """
87 assert isinstance(parent, Item), 'cannot set non-Item as parent.'
88 self.parent = parent
102 def has_parent(self, candidate):
103 """ Whether this item has the given candidate as a parent. """
104 assert candidate != self, 'invalid check of item is self-parent.'
105 if self.parent is None:
106 return False
107 if self.parent == candidate:
108 return True
109 return self.parent.has_parent(candidate)
89 110
90 def add_child(self, child):
111 def add_child(self, candidate):
91 112 """ Add a child to this Item. """ """ Add a child to this Item. """
92 assert isinstance(child, Item), 'cannot set non-Item as child.'
93 assert self.can_have_children(), 'item cannot have children.'
94 children += child
95 child.set_parent(self)
113 assert isinstance(candidate, Item), 'cannot set non-Item as child.'
114 assert candidate != self, 'item cannot add itself as child.'
115 assert self.can_child is not None, 'item cannot have children.'
116 assert candidate.type() in self.can_child, \
117 'candidate item not allowed as child'
118 assert not self.has_parent(candidate), \
119 'candidate is already a parent of item.'
120 self.children.append(candidate)
121 candidate.parent = self
122
123 def type(self):
124 """ Shortcut to the item type name. """
125 return type(self).__name__
96 126
97 127 def name(self, lang=''): def name(self, lang=''):
98 128 """ Name of the item. Return translated value if lang is given. """ """ Name of the item. Return translated value if lang is given. """
99 129 return self._get_value('name', lang=lang) return self._get_value('name', lang=lang)
100 130
131
File helpgen/project.py changed (mode: 100644) (index e69de29..5ad4661)
1 #!/usr/bin/env python
2 """ The project item corresponds to the top-most item. """
3
4 from item import Item
5
6 class Project(Item):
7 metafile = 'helpgen.yml'
8 can_child = ['Category', 'Document']
9
File helpgen/utils.py added (mode: 100644) (index 0000000..13eba53)
1 #!/usr/bin/env python
2
3 from os import path as ospath
4
5 from project import Project
6 from category import Category
7 from document import Document
8
9 def open_item(path):
10 """ Attempts to open the item based on the given folder path. """
11 if not ospath.exists(path):
12 return None
13 if not ospath.isdir(path):
14 return None
15
16 # We check for all known metafile names to try to guess what the item
17 # might be.
18
19 if ospath.exists(ospath.join(path, Project.metafile)):
20 return Project(path)
21 if ospath.exists(ospath.join(path, Category.metafile)):
22 return Category(path)
23 if ospath.exists(ospath.join(path, Document.metafile)):
24 return Document(path)
25 return None
26
27 def child_tree(item, level=0):
28 """ Prints the family tree of the given object. """
29 if item is None:
30 return
31 spaces=''
32 for i in range(level):
33 spaces+=' '
34 print(spaces + str(item))
35 if item.children is None or len(item.children) == 0:
36 return
37 for child in item.children:
38 child_tree(child, level+2)
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/detche/helpgen

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/detche/helpgen

Clone this repository using git:
git clone git://git.rocketgit.com/user/detche/helpgen

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main