├── .gitignore ├── LICENSE ├── README.md ├── onepy ├── __init__.py ├── onepy.py └── onmanager.py ├── setup.py └── tests ├── __init__.py └── test_onepy.py /.gitignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | build/* 3 | MANIFEST 4 | onepy/__pycache__/ 5 | tests/__pycache__/ 6 | .project 7 | .pydevproject 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Varun Srinivasan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | onepy 2 | ===== 3 | 4 | COM Object Model for OneNote 2013 in Python 5 | 6 | 7 | 8 | 9 | #### What are the requirements for onepy? 10 | 11 | * Windows 7 with Python 3.x 12 | * OneNote 2013 or 2010 with your notebooks open 13 | 14 | 15 | #### How do I setup my environment? 16 | 17 | * Install Python 3.4 x86 from [here](https://www.python.org/download/releases/3.4.0/) 18 | * Install PyWin32 for Python 3.4 x86 from [here](http://sourceforge.net/projects/pywin32/files/pywin32/) 19 | * Add `C:\Python34\` to your PATH variable 20 | * Run `C:\Python34\Lib\site-packages\win32com\client\makepy.py` 21 | * Select `Microsoft OneNote 15.0 Extended Type Library` 22 | 23 | 24 | #### How do I submit a new version to the Package Manager? 25 | 26 | * From the repo, run `python.exe setup.py register sdist bdist_wininst upload` 27 | 28 | 29 | #### How do I install onepy? 30 | 31 | `pip install onepy` 32 | 33 | 34 | #### How do I use onepy? 35 | 36 | onepy exposes two main classes - OneNote and ONProcess. 37 | 38 | **OneNote** 39 | 40 | OneNote is an object model class that lets you read content and hierarchy 41 | from the OneNote application. It exposes them as native python types so you 42 | can read OneNote data without having to muck around with the underlying 43 | COM interfaces. 44 | 45 | Updating content via the object model is possible, but not implemented today. 46 | 47 | Use OneNote to read content from notebooks: 48 | ```python 49 | import onepy 50 | 51 | on = onepy.OneNote() 52 | 53 | # print a list of notebooks open in the OneNote 2013 client 54 | for notebook in on.hierarchy: 55 | print (notebook) 56 | ``` 57 | 58 | 59 | **ONProcess** 60 | 61 | ONProcess is a thin python wrapper around the COM interfaces for the [OneNote API](https://msdn.microsoft.com/en-us/library/office/jj680118\(v=office.15\).aspx). 62 | It simplifies starting up the process, choosing the right process when multiple 63 | versions are available and provides more pythonic interfaces for the OneNote 64 | process. 65 | 66 | You'll need to use ONProcess to do anything outside of reading content. Read the 67 | source for onmanager.py for a list of available API calls. 68 | 69 | For example, you can export onenote sections to PDF: 70 | ```python 71 | import onepy 72 | 73 | on = onepy.OneNote() 74 | proc = on.process 75 | 76 | def first_section_id(): 77 | for notebook in on.hierarchy: 78 | for section in notebook: 79 | return section.id 80 | 81 | proc.publish(first_section_id(), "C:\\Users\\Desktop\onepy-test.pdf", 3) 82 | 83 | ``` 84 | 85 | 86 | 87 | #### Common Errors 88 | 89 | ``` 90 | (Office 2013) This COM object can not automate the makepy process - please run makepy manually for this object 91 | ``` 92 | 93 | To work around this, run regedit.exe, and navigate to 94 | ``` 95 | HKEY_CLASSES_ROOT\TypeLib\{0EA692EE-BB50-4E3C-AEF0-356D91732725} 96 | ``` 97 | 98 | There should only be one subfolder in this class called 1.1. If you see 1.0 or any other folders, you'll need to delete them. The final hierarchy should look like this: 99 | 100 | ``` 101 | |- {0EA692EE-BB50-4E3C-AEF0-356D91732725} 102 | | |- 1.1 103 | | |-0 104 | | | |- win32 105 | | |- FLAGDS 106 | | |- HELPDIR 107 | ``` 108 | 109 | Source: [Stack Overflow](http://stackoverflow.com/questions/16287432/python-pywin-onenote-com-onenote-application-15-cannot-automate-the-makepy-p) 110 | -------------------------------------------------------------------------------- /onepy/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | OneNote Object Model in Python 3 | """ 4 | 5 | from __future__ import absolute_import 6 | 7 | from .onepy import ( 8 | OneNote, 9 | Hierarchy, 10 | HierarchyNode, 11 | Notebook, 12 | SectionGroup, 13 | Section, 14 | Page, 15 | Meta, 16 | PageContent, 17 | Title, 18 | Outline, 19 | Position, 20 | Size, 21 | OE, 22 | InsertedFile, 23 | Ink, 24 | Image 25 | ) 26 | 27 | from .onmanager import ONProcess 28 | 29 | __version__ = "0.2.1" -------------------------------------------------------------------------------- /onepy/onepy.py: -------------------------------------------------------------------------------- 1 | from .onmanager import ONProcess 2 | from xml.etree import cElementTree 3 | import os 4 | 5 | # Check for the existing of ON_COM32_VERSION environment variable, 6 | # Default value is set to 15 7 | # Existing value 14 may be used 8 | ON_COM32_VERSION = os.environ.get("ON_COM32_VERSION", 15) 9 | 10 | namespace = "" 11 | 12 | class OneNote(): 13 | 14 | def __init__(self,version=int(ON_COM32_VERSION)): 15 | self.process = ONProcess(version=version) 16 | global namespace 17 | namespace = self.process.namespace 18 | self.object_tree = cElementTree.fromstring(self.process.get_hierarchy("",4)) 19 | self.hierarchy = Hierarchy(self.object_tree) 20 | 21 | def get_page_content(self, page_id, page_info=0): 22 | page_content_xml = cElementTree.fromstring(self.process.get_page_content(page_id, page_info)) 23 | return PageContent(page_content_xml) 24 | 25 | 26 | class Hierarchy(): 27 | 28 | def __init__(self, xml=None): 29 | self._children = [] 30 | if (xml != None): 31 | self.__deserialize_from_xml(xml) 32 | 33 | def __deserialize_from_xml(self, xml): 34 | self._children = [Notebook(n) for n in xml] 35 | 36 | def __iter__(self): 37 | for c in self._children: 38 | yield c 39 | 40 | 41 | class HierarchyNode(): 42 | 43 | def __init__(self, parent=None): 44 | self.name = "" 45 | self.path = "" 46 | self.id = "" 47 | self.last_modified_time = "" 48 | self.synchronized = "" 49 | 50 | def deserialize_from_xml(self, xml): 51 | self.name = xml.get("name") 52 | self.path = xml.get("path") 53 | self.id = xml.get("ID") 54 | self.last_modified_time = xml.get("lastModifiedTime") 55 | 56 | 57 | class Notebook(HierarchyNode): 58 | 59 | def __init__ (self, xml=None): 60 | super().__init__(self) 61 | self.nickname = "" 62 | self.color = "" 63 | self.is_currently_viewed = "" 64 | self.recycleBin = None 65 | self._children = [] 66 | if (xml != None): 67 | self.__deserialize_from_xml(xml) 68 | 69 | def __deserialize_from_xml(self, xml): 70 | HierarchyNode.deserialize_from_xml(self, xml) 71 | self.nickname = xml.get("nickname") 72 | self.color = xml.get("color") 73 | self.is_currently_viewed = xml.get("isCurrentlyViewed") 74 | self.recycleBin = None 75 | for node in xml: 76 | if (node.tag == namespace + "Section"): 77 | self._children.append(Section(node, self)) 78 | 79 | elif (node.tag == namespace + "SectionGroup"): 80 | if(node.get("isRecycleBin")): 81 | self.recycleBin = SectionGroup(node, self) 82 | else: 83 | self._children.append(SectionGroup(node, self)) 84 | 85 | def __iter__(self): 86 | for c in self._children: 87 | yield c 88 | 89 | def __str__(self): 90 | return self.name 91 | 92 | 93 | class SectionGroup(HierarchyNode): 94 | 95 | def __init__ (self, xml=None, parent_node=None): 96 | super().__init__(self) 97 | self.is_recycle_Bin = False 98 | self._children = [] 99 | self.parent = parent_node 100 | if (xml != None): 101 | self.__deserialize_from_xml(xml) 102 | 103 | def __iter__(self): 104 | for c in self._children: 105 | yield c 106 | 107 | def __str__(self): 108 | return self.name 109 | 110 | def __deserialize_from_xml(self, xml): 111 | HierarchyNode.deserialize_from_xml(self, xml) 112 | self.is_recycle_Bin = xml.get("isRecycleBin") 113 | for node in xml: 114 | if (node.tag == namespace + "SectionGroup"): 115 | self._children.append(SectionGroup(node, self)) 116 | if (node.tag == namespace + "Section"): 117 | self._children.append(Section(node, self)) 118 | 119 | 120 | class Section(HierarchyNode): 121 | 122 | def __init__ (self, xml=None, parent_node=None): 123 | super().__init__(self) 124 | self.color = "" 125 | self.read_only = False 126 | self.is_currently_viewed = False 127 | self._children = [] 128 | self.parent = parent_node 129 | if (xml != None): 130 | self.__deserialize_from_xml(xml) 131 | 132 | 133 | def __iter__(self): 134 | for c in self._children: 135 | yield c 136 | 137 | def __str__(self): 138 | return self.name 139 | 140 | 141 | def __deserialize_from_xml(self, xml): 142 | HierarchyNode.deserialize_from_xml(self, xml) 143 | self.color = xml.get("color") 144 | try: 145 | self.read_only = xml.get("readOnly") 146 | except Exception as e: 147 | self.read_only = False 148 | try: 149 | self.is_currently_viewed = xml.get("isCurrentlyViewed") 150 | except Exception as e: 151 | self.is_currently_viewed = False 152 | 153 | self._children = [Page(node, self) for node in xml] 154 | 155 | 156 | class Page(): 157 | 158 | def __init__ (self, xml=None, parent_node=None): 159 | self.name = "" 160 | self.id = "" 161 | self.date_time = "" 162 | self.last_modified_time = "" 163 | self.page_level = "" 164 | self.is_currently_viewed = "" 165 | self._children = [] 166 | self.parent = parent_node 167 | if (xml != None): # != None is required here, since this can return false 168 | self.__deserialize_from_xml(xml) 169 | 170 | def __iter__(self): 171 | for c in self._children: 172 | yield c 173 | 174 | def __str__(self): 175 | return self.name 176 | 177 | # Get / Set Meta 178 | 179 | def __deserialize_from_xml (self, xml): 180 | self.name = xml.get("name") 181 | self.id = xml.get("ID") 182 | self.date_time = xml.get("dateTime") 183 | self.last_modified_time = xml.get("lastModifiedTime") 184 | self.page_level = xml.get("pageLevel") 185 | self.is_currently_viewed = xml.get("isCurrentlyViewed") 186 | self._children = [Meta(node) for node in xml] 187 | 188 | 189 | class Meta(): 190 | 191 | def __init__ (self, xml = None): 192 | self.name = "" 193 | self.content = "" 194 | if (xml!=None): 195 | self.__deserialize_from_xml(xml) 196 | 197 | def __str__(self): 198 | return self.name 199 | 200 | def __deserialize_from_xml (self, xml): 201 | self.name = xml.get("name") 202 | self.id = xml.get("content") 203 | 204 | 205 | class PageContent(): 206 | 207 | def __init__ (self, xml=None): 208 | self.name = "" 209 | self.id = "" 210 | self.date_time = "" 211 | self.last_modified_time = "" 212 | self.page_level = "" 213 | self.lang = "" 214 | self.is_currently_viewed = "" 215 | self._children= [] 216 | self.files = [] 217 | if (xml != None): 218 | self.__deserialize_from_xml(xml) 219 | 220 | def __iter__(self): 221 | for c in self._children: 222 | yield c 223 | 224 | def __str__(self): 225 | return self.name 226 | 227 | def __deserialize_from_xml(self, xml): 228 | self.name = xml.get("name") 229 | self.id = xml.get("ID") 230 | self.date_time = xml.get("dateTime") 231 | self.last_modified_time = xml.get("lastModifiedTime") 232 | self.page_level = xml.get("pageLevel") 233 | self.lang = xml.get("lang") 234 | self.is_currently_viewed = xml.get("isCurrentlyViewed") 235 | for node in xml: 236 | if (node.tag == namespace + "Outline"): 237 | self._children.append(Outline(node)) 238 | elif (node.tag == namespace + "Ink"): 239 | self.files.append(Ink(node)) 240 | elif (node.tag == namespace + "Image"): 241 | self.files.append(Image(node)) 242 | elif (node.tag == namespace + "InsertedFile"): 243 | self.files.append(InsertedFile(node)) 244 | elif (node.tag == namespace + "MediaFile"): 245 | self.files.append(MediaFile(node, self)) 246 | elif (node.tag == namespace + "Title"): 247 | self._children.append(Title(node)) 248 | elif (node.tag == namespace + "MediaPlaylist"): 249 | self.media_playlist = MediaPlaylist(node, self) 250 | 251 | 252 | class Title(): 253 | 254 | def __init__ (self, xml=None): 255 | self.style = "" 256 | self.lang = "" 257 | self._children = [] 258 | if (xml != None): 259 | self.__deserialize_from_xml(xml) 260 | 261 | def __str__ (self): 262 | return "Page Title" 263 | 264 | def __iter__ (self): 265 | for c in self._children: 266 | yield c 267 | 268 | def __deserialize_from_xml(self, xml): 269 | self.style = xml.get("style") 270 | self.lang = xml.get("lang") 271 | for node in xml: 272 | if (node.tag == namespace + "OE"): 273 | self._children.append(OE(node, self)) 274 | 275 | 276 | class Outline(): 277 | 278 | def __init__ (self, xml=None): 279 | self.author = "" 280 | self.author_initials = "" 281 | self.last_modified_by = "" 282 | self.last_modified_by_initials = "" 283 | self.last_modified_time = "" 284 | self.id = "" 285 | self._children = [] 286 | if (xml != None): 287 | self.__deserialize_from_xml(xml) 288 | 289 | def __iter__(self): 290 | for c in self._children: 291 | yield c 292 | 293 | def __str__(self): 294 | return "Outline" 295 | 296 | def __deserialize_from_xml (self, xml): 297 | self.author = xml.get("author") 298 | self.author_initials = xml.get("authorInitials") 299 | self.last_modified_by = xml.get("lastModifiedBy") 300 | self.last_modified_by_initials = xml.get("lastModifiedByInitials") 301 | self.last_modified_time = xml.get("lastModifiedTime") 302 | self.id = xml.get("objectID") 303 | append = self._children.append 304 | for node in xml: 305 | if (node.tag == namespace + "OEChildren"): 306 | for childNode in node: 307 | if (childNode.tag == namespace + "OE"): 308 | append(OE(childNode, self)) 309 | 310 | 311 | class Position(): 312 | 313 | def __init__ (self, xml=None, parent_node=None): 314 | self.x = "" 315 | self.y = "" 316 | self.z = "" 317 | self.parent = parent_node 318 | if (xml!=None): 319 | self.__deserialize_from_xml(xml) 320 | 321 | def __deserialize_from_xml(self, xml): 322 | self.x = xml.get("x") 323 | self.y = xml.get("y") 324 | self.z = xml.get("z") 325 | 326 | 327 | class Size(): 328 | 329 | def __init__ (self, xml=None, parent_node=None): 330 | self.width = "" 331 | self.height = "" 332 | self.parent = parent_node 333 | if (xml!=None): 334 | self.__deserialize_from_xml(xml) 335 | 336 | def __deserialize_from_xml(self, xml): 337 | self.width = xml.get("width") 338 | self.height = xml.get("height") 339 | 340 | 341 | class OE(): 342 | 343 | def __init__ (self, xml=None, parent_node=None): 344 | 345 | self.creation_time = "" 346 | self.last_modified_time = "" 347 | self.last_modified_by = "" 348 | self.id = "" 349 | self.alignment = "" 350 | self.quick_style_index = "" 351 | self.style = "" 352 | self.text = "" 353 | self._children = [] 354 | self.parent = parent_node 355 | self.files = [] 356 | self.media_indices = [] 357 | if (xml != None): 358 | self.__deserialize_from_xml(xml) 359 | 360 | def __iter__(self): 361 | for c in self._children: 362 | yield c 363 | 364 | def __str__(self): 365 | try: 366 | return self.text 367 | except AttributeError: 368 | return "Empty OE" 369 | 370 | def __deserialize_from_xml(self, xml): 371 | self.creation_time = xml.get("creationTime") 372 | self.last_modified_time = xml.get("lastModifiedTime") 373 | self.last_modified_by = xml.get("lastModifiedBy") 374 | self.id = xml.get("objectID") 375 | self.alignment = xml.get("alignment") 376 | self.quick_style_index = xml.get("quickStyleIndex") 377 | self.style = xml.get("style") 378 | 379 | for node in xml: 380 | if (node.tag == namespace + "T"): 381 | if (node.text != None): 382 | self.text = node.text 383 | else: 384 | self.text = "NO TEXT" 385 | 386 | elif (node.tag == namespace + "OEChildren"): 387 | for childNode in node: 388 | if (childNode.tag == namespace + "OE"): 389 | self._children.append(OE(childNode, self)) 390 | 391 | elif (node.tag == namespace + "Image"): 392 | self.files.append(Image(node, self)) 393 | 394 | elif (node.tag == namespace + "InkWord"): 395 | self.files.append(Ink(node, self)) 396 | 397 | elif (node.tag == namespace + "InsertedFile"): 398 | self.files.append(InsertedFile(node, self)) 399 | 400 | elif (node.tag == namespace + "MediaFile"): 401 | self.files.append(MediaFile(node, self)) 402 | 403 | elif (node.tag == namespace + "MediaIndex"): 404 | self.media_indices.append(MediaIndex(node, self)) 405 | 406 | 407 | class InsertedFile(): 408 | 409 | # need to add position data to this class 410 | 411 | def __init__ (self, xml=None, parent_node=None): 412 | self.path_cache = "" 413 | self.path_source = "" 414 | self.preferred_name = "" 415 | self.last_modified_time = "" 416 | self.last_modified_by = "" 417 | self.id = "" 418 | self.parent = parent_node 419 | if (xml != None): 420 | self.__deserialize_from_xml(xml) 421 | 422 | def __iter__ (self): 423 | yield None 424 | 425 | def __str__(self): 426 | try: 427 | return self.preferredName 428 | except AttributeError: 429 | return "Unnamed File" 430 | 431 | def __deserialize_from_xml(self, xml): 432 | self.path_cache = xml.get("pathCache") 433 | self.path_source = xml.get("pathSource") 434 | self.preferred_name = xml.get("preferredName") 435 | self.last_modified_time = xml.get("lastModifiedTime") 436 | self.last_modified_by = xml.get("lastModifiedBy") 437 | self.id = xml.get("objectID") 438 | 439 | 440 | class MediaReference(): 441 | def __init__ (self, xml=None, parent_node=None): 442 | self.media_id = "" 443 | 444 | def __iter__ (self): 445 | yield None 446 | 447 | def __str__(self): 448 | return "Media Reference" 449 | 450 | def __deserialize_from_xml(self, xml): 451 | self.media_id = xml.get("mediaID") 452 | 453 | 454 | class MediaPlaylist(): 455 | def __init__ (self, xml=None, parent_node=None): 456 | self.media_references = [] 457 | 458 | def __iter__(self): 459 | for c in self.media_references: 460 | yield c 461 | 462 | def __str__(self): 463 | return "Media Index" 464 | 465 | def __deserialize_from_xml(self, xml): 466 | for node in xml: 467 | if (node.tag == namespace + "MediaReference"): 468 | self.media_references.append(MediaReference(node, self)) 469 | 470 | 471 | class MediaIndex(): 472 | def __init__ (self, xml=None, parent_node=None): 473 | self.media_reference = None 474 | self.time_index = 0 475 | 476 | def __iter__(self): 477 | yield None 478 | 479 | def __str__(self): 480 | return "Media Index" 481 | 482 | def __deserialize_from_xml(self, xml): 483 | self.time_index = xml.get("timeIndex") 484 | for node in xml: 485 | if (node.tag == namespace + "MediaReference"): 486 | self.media_reference = MediaReference(node, self) 487 | 488 | 489 | class MediaFile(InsertedFile): 490 | def __init__ (self, xml=None, parent_node=None): 491 | self.media_reference = None 492 | super().__init__(xml, parent_node) 493 | 494 | def __iter__(self): 495 | yield None 496 | 497 | def __str__(self): 498 | try: 499 | return self.preferredName 500 | except AttributeError: 501 | return "Unnamed Media File" 502 | 503 | def __deserialize_from_xml(self, xml): 504 | super().__deserialize_from_xml(xml) 505 | for node in xml: 506 | if (node.tag == namespace + "MediaReference"): 507 | self.media_reference = MediaReference(node, self) 508 | 509 | 510 | class Ink(): 511 | 512 | # need to add position data to this class 513 | 514 | def __init__ (self, xml=None, parent_node=None): 515 | self.recognized_text = "" 516 | self.x = "" 517 | self.y = "" 518 | self.ink_origin_x = "" 519 | self.ink_origin_y = "" 520 | self.width = "" 521 | self.height = "" 522 | self.data = "" 523 | self.callback_id = "" 524 | self.parent = parent_node 525 | 526 | if (xml != None): 527 | self.__deserialize_from_xml(xml) 528 | 529 | def __iter__ (self): 530 | yield None 531 | 532 | def __str__(self): 533 | try: 534 | return self.recognizedText 535 | except AttributeError: 536 | return "Unrecognized Ink" 537 | 538 | def __deserialize_from_xml(self, xml): 539 | self.recognized_text = xml.get("recognizedText") 540 | self.x = xml.get("x") 541 | self.y = xml.get("y") 542 | self.ink_origin_x = xml.get("inkOriginX") 543 | self.ink_origin_y = xml.get("inkOriginY") 544 | self.width = xml.get("width") 545 | self.height = xml.get("height") 546 | 547 | for node in xml: 548 | if (node.tag == namespace + "CallbackID"): 549 | self.callback_id = node.get("callbackID") 550 | elif (node.tag == namespace + "Data"): 551 | self.data = node.text 552 | 553 | 554 | class Image(): 555 | 556 | def __init__ (self, xml=None, parent_node=None): 557 | self.format = "" 558 | self.original_page_number = "" 559 | self.last_modified_time = "" 560 | self.id = "" 561 | self.callback_id = None 562 | self.data = "" 563 | self.parent = parent_node 564 | if (xml != None): 565 | self.__deserialize_from_xml(xml) 566 | 567 | def __iter__ (self): 568 | yield None 569 | 570 | def __str__(self): 571 | return self.format + " Image" 572 | 573 | def __deserialize_from_xml(self, xml): 574 | self.format = xml.get("format") 575 | self.original_page_number = xml.get("originalPageNumber") 576 | self.last_modified_time = xml.get("lastModifiedTime") 577 | self.id = xml.get("objectID") 578 | for node in xml: 579 | if (node.tag == namespace + "CallbackID"): 580 | self.callback_id = node.get("callbackID") 581 | elif (node.tag == namespace + "Data"): 582 | if (node.text != None): 583 | self.data = node.text 584 | 585 | -------------------------------------------------------------------------------- /onepy/onmanager.py: -------------------------------------------------------------------------------- 1 | import win32com.client 2 | import pywintypes as pwt 3 | 4 | if win32com.client.gencache.is_readonly == True: 5 | win32com.client.gencache.is_readonly = False 6 | win32com.client.gencache.Rebuild() 7 | 8 | """ 9 | OnePy 10 | Provides pythonic wrappers around OneNote COM interfaces 11 | """ 12 | 13 | ON15_APP_ID = 'OneNote.Application.15' 14 | ON15_SCHEMA = "{http://schemas.microsoft.com/office/onenote/2013/onenote}" 15 | ON14_APP_ID = 'OneNote.Application.14' 16 | ON14_SCHEMA = "{http://schemas.microsoft.com/office/onenote/2010/onenote}" 17 | 18 | 19 | class ONProcess(): 20 | 21 | def __init__(self, version=15): 22 | 23 | try: 24 | if (version == 15): 25 | self.process = win32com.client.gencache.EnsureDispatch(ON15_APP_ID) 26 | self.namespace = ON15_SCHEMA 27 | if (version == 14): 28 | self.process = win32com.client.gencache.EnsureDispatch(ON14_APP_ID) 29 | self.namespace = ON14_SCHEMA 30 | except Exception as e: 31 | print (e) 32 | print("error starting onenote {}".format(version)) 33 | 34 | 35 | def get_hierarchy(self, start_node_id="", hierarchy_scope=4): 36 | """ 37 | HierarchyScope 38 | 0 - Gets just the start node specified and no descendants. 39 | 1 - Gets the immediate child nodes of the start node, and no descendants in higher or lower subsection groups. 40 | 2 - Gets all notebooks below the start node, or root. 41 | 3 - Gets all sections below the start node, including sections in section groups and subsection groups. 42 | 4 - Gets all pages below the start node, including all pages in section groups and subsection groups. 43 | """ 44 | return (self.process.GetHierarchy(start_node_id, hierarchy_scope)) 45 | 46 | def update_hierarchy(self, changes_xml_in): 47 | try: 48 | self.process.UpdateHierarchy(changes_xml_in) 49 | except Exception as e: 50 | print(e) 51 | print("Could not Update Hierarchy") 52 | 53 | def open_hierarchy(self, path, relative_to_object_id, object_id, create_file_type=0): 54 | """ 55 | CreateFileType 56 | 0 - Creates no new object. 57 | 1 - Creates a notebook with the specified name at the specified location. 58 | 2 - Creates a section group with the specified name at the specified location. 59 | 3 - Creates a section with the specified name at the specified location. 60 | """ 61 | try: 62 | return(self.process.OpenHierarchy(path, relative_to_object_id, "", create_file_type)) 63 | except Exception as e: 64 | print(e) 65 | print("Could not Open Hierarchy") 66 | 67 | 68 | def delete_hierarchy (self, object_id, last_modified): 69 | try: 70 | self.process.DeleteHierarchy(object_id, pwt.Time(last_modified)) 71 | except Exception as e: 72 | print(e) 73 | print("Could not Delete Hierarchy") 74 | 75 | def create_new_page (self, section_id, new_page_style=0): 76 | """ 77 | NewPageStyle 78 | 0 - Create a Page that has Default Page Style 79 | 1 - Create a blank page with no title 80 | 2 - Createa blank page that has no title 81 | """ 82 | try: 83 | self.process.CreateNewPage(section_id, "", new_page_style) 84 | except Exception as e: 85 | print(e) 86 | print("Unable to create the page") 87 | 88 | def close_notebook(self, notebook_id): 89 | try: 90 | self.process.CloseNotebook(notebook_id) 91 | except Exception as e: 92 | print(e) 93 | print("Could not Close Notebook") 94 | 95 | def get_page_content(self, page_id, page_info=0): 96 | """ 97 | PageInfo 98 | 0 - Returns only basic page content, without selection markup and binary data objects. This is the standard value to pass. 99 | 1 - Returns page content with no selection markup, but with all binary data. 100 | 2 - Returns page content with selection markup, but no binary data. 101 | 3 - Returns page content with selection markup and all binary data. 102 | """ 103 | try: 104 | return(self.process.GetPageContent(page_id, "", page_info)) 105 | except Exception as e: 106 | print(e) 107 | print("Could not get Page Content") 108 | 109 | def update_page_content(self, page_changes_xml_in, last_modified): 110 | try: 111 | self.process.UpdatePageContent(page_changes_xml_in, pwt.Time(last_modified)) 112 | except Exception as e: 113 | print(e) 114 | print("Could not Update Page Content") 115 | 116 | def get_binary_page_content(self, page_id, callback_id): 117 | try: 118 | return(self.process.GetBinaryPageContent(page_id, callback_id)) 119 | except Exception as e: 120 | print(e) 121 | print("Could not Get Binary Page Content") 122 | 123 | def delete_page_content(self, page_id, object_id, last_modified): 124 | try: 125 | self.process.DeletePageContent(page_id, object_id, pwt.Time(last_modified)) 126 | except Exception as e: 127 | print(e) 128 | print("Could not Delete Page Content") 129 | 130 | 131 | # Actions 132 | 133 | 134 | def navigate_to(self, object_id, new_window=False): 135 | try: 136 | self.process.NavigateTo(object_id, "", new_window) 137 | except Exception as e: 138 | print(e) 139 | print("Could not Navigate To") 140 | 141 | def publish(self, hierarchy_id, target_file_path, publish_format, clsid_of_exporter=""): 142 | """ 143 | PublishFormat 144 | 0 - Published page is in .one format. 145 | 1 - Published page is in .onea format. 146 | 2 - Published page is in .mht format. 147 | 3 - Published page is in .pdf format. 148 | 4 - Published page is in .xps format. 149 | 5 - Published page is in .doc or .docx format. 150 | 6 - Published page is in enhanced metafile (.emf) format. 151 | """ 152 | try: 153 | self.process.Publish(hierarchy_id, target_file_path, publish_format, clsid_of_exporter) 154 | except Exception as e: 155 | print(e) 156 | print("Could not Publish") 157 | 158 | def open_package(self, path_package, path_dest): 159 | try: 160 | return(self.process.OpenPackage(path_package, path_dest)) 161 | except Exception as e: 162 | print(e) 163 | print("Could not Open Package") 164 | 165 | def get_hyperlink_to_object(self, hierarchy_id, target_file_path=""): 166 | try: 167 | return(self.process.GetHyperlinkToObject(hierarchy_id, target_file_path)) 168 | except Exception as e: 169 | print(e) 170 | print("Could not Get Hyperlink") 171 | 172 | def find_pages(self, start_node_id, search_string, display): 173 | try: 174 | return(self.process.FindPages(start_node_id, search_string, "", False, display)) 175 | except Exception as e: 176 | print(e) 177 | print("Could not Find Pages") 178 | 179 | def get_special_location(self, special_location=0): 180 | """ 181 | SpecialLocation 182 | 0 - Gets the path to the Backup Folders folder location. 183 | 1 - Gets the path to the Unfiled Notes folder location. 184 | 2 - Gets the path to the Default Notebook folder location. 185 | """ 186 | try: 187 | return(self.process.GetSpecialLocation(special_location)) 188 | except Exception as e: 189 | print(e) 190 | print("Could not retreive special location") 191 | 192 | def get_parent(self, object_id): 193 | try: 194 | return(self.process.GetHierarchyParent(object_id)) 195 | except Exception as e: 196 | print(e) 197 | print("Could not retrieve parent object") 198 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from distutils.core import setup 3 | 4 | 5 | def get_version(): 6 | with open(os.path.join('onepy', '__init__.py')) as f: 7 | for line in f: 8 | if line.startswith('__version__ ='): 9 | return line.split('=')[1].strip().strip('"\'') 10 | 11 | 12 | setup( 13 | name = 'onepy', 14 | packages = ['onepy'], 15 | version = get_version(), 16 | description = 'OneNote Object Model', 17 | author='Varun Srinivasan', 18 | author_email='varunsrin@gmail.com', 19 | url="https://github.com/varunsrin/one-py", 20 | classifiers=[ 21 | 'Development Status :: 3 - Alpha', 22 | 'Intended Audience :: Developers', 23 | 'Natural Language :: English', 24 | 'License :: OSI Approved :: MIT License', 25 | 'Environment :: Win32 (MS Windows)', 26 | 'Operating System :: Microsoft :: Windows', 27 | 'Programming Language :: Python', 28 | 'Programming Language :: Python :: 3', 29 | 'Topic :: Software Development :: Libraries :: Python Modules', 30 | ], 31 | test_suite="tests" 32 | ) -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | OneNote Object Model in Python 3 | """ 4 | 5 | import unittest 6 | 7 | if __name__ == '__main__': 8 | unittest.main() -------------------------------------------------------------------------------- /tests/test_onepy.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests & Stuff 3 | """ 4 | 5 | import unittest 6 | from onepy import OneNote 7 | 8 | on = OneNote() 9 | 10 | #lists all sections & notebooks open in onenote 11 | 12 | 13 | class TestOneNote(unittest.TestCase): 14 | 15 | def test_instance(self): 16 | for nbk in on.hierarchy: 17 | print (nbk) 18 | if nbk.name == "SoundFocus": 19 | for s in nbk: 20 | print (" " + str(s)) 21 | for page in s: 22 | print (" " + str(page.name.encode('ascii', 'ignore'))) 23 | 24 | 25 | #print(on.get_page_content("{37B075B6-358E-04DA-193E-73D0AD300DA3}{1}{B0}")) 26 | 27 | self.assertEqual(True, True) 28 | 29 | if __name__ == '__main__': 30 | unittest.main() --------------------------------------------------------------------------------