How-to guide¶
This section is a series of helpful recipes for how to do things and solve particular problems with mosromgr.
Note
These examples deal with MOS messages read from local files, but
MosFile
and
MosCollection
objects can also be
constructed using from_string
and
from_s3
. Refer to API - MOS Types
and API - MOS Collection for more information.
Merging MOS files¶
When dealing with merging MosFile
objects, this is
done by “adding” each file to the RunningOrder
object by using the +
operator:
>>> from mosromgr.mostypes import RunningOrder, StoryInsert
>>> ro = RunningOrder.from_file('123456-roCreate.mos.xml')
>>> ss = StoryInsert.from_file('123457-roStoryInsert.mos.xml')
>>> len(ro.stories)
10
>>> ro += ss
>>> len(ro.stories)
11
To parse and merge a collection of MOS files, you could create a list of files
(or use glob()
), let MosFile
classify
each file, then merge each of them into the
RunningOrder
:
from mosromgr.mostypes import MosFile
from glob import glob
files = glob('*.mos.xml')
ro, *mosfiles = sorted(MosFile.from_file(f) for f in files)
for mf in mosfiles:
ro += mf
To access the final XML, simply print the
RunningOrder
object or access the
__str__
:
>>> print(ro)
<mos>
<mosID>MOS ID</mosID>
<messageID>1234567</messageID>
...
>>> s = str(ro)
>>> s
<mos>
<mosID>MOS ID</mosID>
<messageID>1234567</messageID>
...
Merging MOS files using MOSCollection¶
The MosCollection
class provides a wrapper for
operations dealing with a collection of MOS files as part of one programme. So
to merge files like in the previous example, you could do the following
instead:
from mosromgr.moscollection import MosCollection
from glob import glob
files = glob('*.mos.xml')
mc = MosCollection.from_files(files)
mc.merge()
To access the final XML, simply print the
MosCollection
object or access the
__str__
:
>>> print(mc)
<mos>
<mosID>MOS ID</mosID>
<messageID>1234567</messageID>
...
>>> s = str(mc)
>>> s
<mos>
<mosID>MOS ID</mosID>
<messageID>1234567</messageID>
...
Accessing the properties of a running order¶
For example, a RunningOrder
object could contain
several Story
objects, each containing a number
of Item
objects:
>>> from mosromgr.mostypes import RunningOrder
>>> ro = RunningOrder.from_file('roCreate.mos.xml')
>>> ro.stories
[<Story 1234>, <Story 1235>, <Story 1236>]
>>> [story.duration for story in ro.stories]
[10, 20, 30]
>>> ro.duration
60
>>> story = ro.stories[0]
>>> story.slug
'Some story'
>>> story.items
[<Item ITEM1>, <Item ITEM2>, <Item ITEM3>]
>>> item = story.items[0]
>>> item.slug
'Some item'
In the case of a StoryAppend
object, this would
contain a single story:
>>> from mosromgr.mostypes import StoryAppend
>>> sa = StoryAppend.from_file('roStoryAppend.mos.xml')
>>> sa.story
<Story STORY1>
>>> sa.duration
20
If this StoryAppend
object was merged with a
RunningOrder
object, the new story would be
accessible in the RunningOrder
stories
property:
>>> from mosromgr.mostypes import RunningOrder, StoryAppend
>>> ro = RunningOrder.from_file('roCreate.mos.xml')
>>> sa = StoryAppend.from_file('roStoryAppend.mos.xml')
>>> len(ro.stories)
3
>>> ro += sa
>>> len(ro.stories)
4
Note
Note that these classes should not normally be constructed by the user, but
instances of them can be found within MosFile
objects, so the following documentation is provided as a reference to how
they can be used.
Note
Note that additional information may be contained within the XML, and these
elements are simply an abstraction providing easy access to certain
elements. In the sprit of escape hatches and ejector seats, the original
XML in which the element was found is accessible as an
xml.etree.ElementTree.Element
object for further introspection.
Handling Exceptions¶
This can be useful for handling exceptions in your own code. For example, to
handle any exception generated by the library, you can catch the library’s base
exception MosRoMgrException
:
try:
main()
except MosRoMgrException as e:
print(e)
To catch a specific exception known to be raised under certain circumstances, each exception can be imported and handled separately if required:
from mosromgr.mostypes import MosFile
from mosromgr.exc import MosInvalidXML, UnknownMosFileType
try:
ro = MosFile.from_file(mosfile)
except MosInvalidXML as e:
print("Invalid in", mosfile)
except UnknownMosFileType as e:
print("Unknown MOS file type", mosfile)
In some cases, a warning is raised rather than an exception. This means that
execution is continued but a warning is output, which can be suppressed using
the warnings
module.
Capturing warnings¶
If you want to catch warnings and log them (for example, during a merge), you
can use warnings.catch_warnings
:
with warnings.catch_warnings(record=True) as warns:
mc.merge()
warning_messages = [str(w.message) for w in warns]
Suppressing warnings¶
If you are not interested in seeing or capturing warnings, you can either use a
warning filter or use warnings.catch_warnings
:
with warnings.catch_warnings() as warns:
mc.merge()
Using the command line interface¶
The mosromgr
command provided includes a number of subcommands. Running
mosromgr
alone will show the general help message, and running a subcommand
without arguments will show the help message for that subcommand.
Detecting MOS file types¶
To detect the type of a MOS file, use the mosromgr detect command:
$ mosromgr detect -f 123456-roCreate.mos.xml
123456-roCreate.mos.xml: RunningOrder
Multiple files can be provided as arguments:
$ mosromgr detect -f 123456-roCreate.mos.xml 123457-roStorySend.mos.xml
123456-roCreate.mos.xml: RunningOrder
123457-roStorySend.mos.xml: StorySend
Wildcards can also be used:
$ mosromgr detect *
123456-roCreate.mos.xml: RunningOrder
123457-roStorySend.mos.xml: StorySend
...
9148627-roDelete.mos.xml: RunningOrderEnd
bbcProgrammeMetadata.xml: Unknown MOS file type
cricket: Invalid
FINAL.json: Invalid
FINAL.xml: RunningOrder (completed)
You can also read files from an S3 bucket. Either a specific file by key:
$ mosromgr detect -b my-bucket -k newsnight/20210101/123456-roCreate.mos.xml
INFO:botocore.credentials:Found credentials in environment variables.
OPENMEDIA_NCS.W1.BBC.MOS/OM_10.1253459/5744992-roCreate.mos.xml: RunningOrder
Or a whole folder by prefix:
$ mosromgr detect -b bbc-newslabs-slicer-mos-message-store -p newsnight/20210101/
INFO:botocore.credentials:Found credentials in environment variables.
newsnight/20210101/123456-roCreate.mos.xml: RunningOrder
newsnight/20210101/123457-roStorySend.mos.xml: StorySend
newsnight/20210101/123458-roStorySend.mos.xml: StorySend
newsnight/20210101/123459-roStorySend.mos.xml: StorySend
...
Inspecting a running order¶
To inspect the contents of a roCreate
file, use the
mosromgr inspect command:
$ mosromgr inspect -f 123456-roCreate.mos.xml
22:45 NEWSNIGHT 54D CORE Thu, 08.04.2021
Many options are available which allow for inspecting a file from an S3 bucket
(-b
and -k
) instead of a local file (-f
); and others which affect the
output such as -t
(start time), -d
(duration), -s
(stories):
$ mosromgr inspect -b my-bucket -k newsnight/20210804/123456-roCreate.mos.xml -tds
22:45 NEWSNIGHT 54D CORE Thu, 08.04.2021
Start time: 2021-04-08 21:46
Duration: 0:35:09
MENU START
MENU-PRE TITLE TEASE
MENU-TITLES
MENU-POST TITLE "ALSO TONIGHT"
NORTHERN IRELAND-INTRO
NORTHERN IRELAND-LEWIS PACKAGE
...
END OF PROGRAMME
Merging MOS files¶
To merge a set of MOS files for a programme, use the mosromgr merge command.
Merging local files:
$ mosromgr merge -f *.mos.xml -o FINAL.xml
...
INFO:mosromgr.moscollection:Merging RunningOrderEnd 123499
INFO:mosromgr.moscollection:Completed merging 99 mos files
Writing merged running order to FINAL.xml
Or files in an S3 bucket folder by prefix:
$ mosromgr merge -b my-bucket -p newsnight/20210101/ -o
...
INFO:mosromgr.moscollection:Merging RunningOrderEnd 123499
INFO:mosromgr.moscollection:Completed merging 99 mos files
Writing merged running order to FINAL.xml