s:

>>> p = converter.parse('tinynotation: 3/4 C4 D E 2/4 F G A B 1/4 c')
>>> p
<music21.stream.Part 0x104ce64e0>

>>> p.show('t')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.clef.BassClef>
    {0.0} <music21.meter.TimeSignature 3/4>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
{3.0} <music21.stream.Measure 2 offset=3.0>
    {0.0} <music21.meter.TimeSignature 2/4>
    {0.0} <music21.note.Note F>
    {1.0} <music21.note.Note G>
{5.0} <music21.stream.Measure 3 offset=5.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
{7.0} <music21.stream.Measure 4 offset=7.0>
    {0.0} <music21.meter.TimeSignature 1/4>
    {0.0} <music21.note.Note C>
    {1.0} <music21.bar.Barline type=final>

Let's get the last two notes of the piece, the B and high c:

>>> m4 = p.measure(4)
>>> c = m4.notes.first()
>>> c
<music21.note.Note C>

>>> m3 = p.measure(3)
>>> b = m3.notes.last()
>>> b
<music21.note.Note B>

Now when we run `getContextByClass(meter.TimeSignature)` on c, we get a
time signature of 1/4.

>>> c.getContextByClass(meter.TimeSignature)
<music21.meter.TimeSignature 1/4>

Doing what we just did wouldn't be hard to do with other methods,
though `getContextByClass` makes it easier.  But the time signature
context for b would be much harder to get without this method, since in
order to do it, it searches backwards within the measure, finds that
there's nothing there.  It goes to the previous measure and searches
inside that one from the end backwards until it gets the proper
TimeSignature of 2/4:

>>> b.getContextByClass(meter.TimeSignature)
<music21.meter.TimeSignature 2/4>

For backwards compatibility you can also pass in a string of the
class name:

>>> b.getContextByClass('TimeSignature')
<music21.meter.TimeSignature 2/4>

But if you use Python typing or a typing-aware IDE, then the first call
(with class name) will signal that it is returning a TimeSignature object
and allow for error detection, autocomplete, etc.  The latter call
(with string) will only know that some Music21Object was returned.

The method is smart enough to stop when it gets to the beginning of the
part.  This is all you need to know for most uses.  The rest of the
docs are for advanced uses:

The method searches Sites and also associated objects to find a
matching class. Returns `None` if no match is found.

A reference to the caller is required to find the offset of the object
of the caller.

The caller may be a Sites reference from a lower-level object.  If so,
we can access the location of that lower-level object. However, if we
need a flat representation, the caller needs to be the source Stream,
not its Sites reference.

The `getElementMethod` is an enum value (new in v7) from
:class:`~music21.common.enums.ElementSearch` that selects which
Stream method is used to get elements for searching. (The historical form
of supplying one of the following values as a string is also supported.)

>>> from music21.common.enums import ElementSearch
>>> [x for x in ElementSearch]
[<ElementSearch.BEFORE>,
 <ElementSearch.AFTER>,
 <ElementSearch.AT_OR_BEFORE>,
 <ElementSearch.AT_OR_AFTER>,
 <ElementSearch.BEFORE_OFFSET>,
 <ElementSearch.AFTER_OFFSET>,
 <ElementSearch.AT_OR_BEFORE_OFFSET>,
 <ElementSearch.AT_OR_AFTER_OFFSET>,
 <ElementSearch.BEFORE_NOT_SELF>,
 <ElementSearch.AFTER_NOT_SELF>,
 <ElementSearch.ALL>]

The "after" do forward contexts -- looking ahead.

Demonstrations of these keywords:

Because `b` is a `Note`, `.getContextByClass(note.Note)` will only find itself:

>>> b.getContextByClass(note.Note) is b
True

To get the previous `Note`, use `getElementMethod=ElementSearch.BEFORE`:

>>> a = b.getContextByClass(note.Note, getElementMethod=ElementSearch.BEFORE)
>>> a
<music21.note.Note A>

This is similar to `.previous(note.Note)`, though that method is a bit more
sophisticated:

>>> b.previous(note.Note)
<music21.note.Note A>

To get the following `Note` use `getElementMethod=ElementSearch.AFTER`:

>>> c = b.getContextByClass(note.Note, getElementMethod=ElementSearch.AFTER)
>>> c
<music21.note.Note C>

This is similar to `.next(note.Note)`, though, again, that method is a bit more
sophisticated:

>>> b.next(note.Note)
<music21.note.Note C>

A Stream might contain several elements at the same offset, leading to
potentially surprising results where searching by `ElementSearch.AT_OR_BEFORE`
does not find an element that is technically the NEXT node but still at 0.0:

>>> s = stream.Stream()
>>> s.insert(0, clef.BassClef())
>>> s.next()
<music21.clef.BassClef>
>>> s.getContextByClass(clef.Clef) is None
True
>>> s.getContextByClass(clef.Clef, getElementMethod=ElementSearch.AT_OR_AFTER)
<music21.clef.BassClef>

This can be remedied by explicitly searching by offsets:

>>> s.getContextByClass(clef.Clef, getElementMethod=ElementSearch.AT_OR_BEFORE_OFFSET)
<music21.clef.BassClef>

Or by not limiting the search by temporal position at all:

>>> s.getContextByClass(clef.Clef, getElementMethod=ElementSearch.ALL)
<music21.clef.BassClef>

Notice that if searching for a `Stream` context, the element is not
guaranteed to be in that Stream.  This is obviously true in this case:

>>> p2 = stream.Part()
>>> m = stream.Measure(number=1)
>>> p2.insert(0, m)
>>> n = note.Note('D')
>>> m.insert(2.0, n)
>>> try:
...     n.getContextByClass(stream.Part).elementOffset(n)
... except Music21Exception:
...     print('not there')
not there

But it is less clear with something like this:

>>> import copy
>>> n2 = copy.deepcopy(n)
>>> try:
...     n2.getContextByClass(stream.Measure).elementOffset(n2)
... except Music21Exception:
...     print('not there')
not there

A measure context is being found, but only through the derivation chain.

>>> n2.getContextByClass(stream.Measure)
<music21.stream.Measure 1 offset=0.0>

To prevent this error, use the `followDerivation=False` setting

>>> print(n2.getContextByClass(stream.Measure, followDerivation=False))
None

Or if you want the offset of the element following the derivation chain,
call `getOffsetBySite()` on the object:

>>> n2.getOffsetBySite(n2.getContextByClass(stream.Measure))
2.0


Raises `ValueError` if `getElementMethod` is not a value in `ElementSearch`.

>>> n2.getContextByClass(expressions.TextExpression, getElementMethod='invalid')
Traceback (most recent call last):
ValueError: Invalid getElementMethod: invalid

Raises `ValueError` for incompatible values `followDerivation=True`
and `priorityTargetOnly=True`.

* Changed in v5.7: added followDerivation=False and made
  everything but the class keyword only
* New in v6: added priorityTargetOnly -- see contextSites for description.
* New in v7: added getElementMethod `all` and `ElementSearch` enum.
* Changed in v8: class-based calls return properly typed items.  Putting
  multiple types into className (never documented) is no longer allowed.

OMIT_FROM_DOCS

Testing that this works:

>>> import gc
>>> _ = gc.collect()
>>> for site, positionStart, searchType in b.contextSites(
...                                 returnSortTuples=True,
...                                 sortByCreationTime=False,
...                                 followDerivation=True
...                                 ):
...     print(site, positionStart, searchType)
<music21.stream.Measure 3 offset=5.0> SortTuple(atEnd=0, offset=1.0, ...) elementsFirst
<music21.stream.Part 0x1118cadd8> SortTuple(atEnd=0, offset=6.0, ...) flatten
c