Skip to main content

Poetic processing, for Python

Project description

Poesy

Poetic processing, for Python

Code developed in the Stanford Literary Lab's "Transhistorical Poetry Project" by Ryan Heuser (@quadrismegistus), J.D. Porter, Jonathan Sensenbaugh, Justin Tackett, Mark Algee-Hewitt, and Maria Kraxenberger. Cleaned and modified from its original form in 2018.

Poesy is built on Prosodic, a metrical-phonological parser written in Python.

What's new in 0.4: poesy is now a thin compatibility layer over prosodic v3, which absorbed poesy's poem-level analysis (meter-type classification, line/syllable scheme detection, rhyme-scheme matching, sonnet detection) into its prosodic.analysis module. The classic Poem API below is preserved; the heavy lifting happens in prosodic. If you're starting fresh, consider using prosodic v3 directly (text.meter_type, text.rhyme_scheme, text.is_sonnet, text.summary()); if you have poesy code, it should keep working. The underlying prosodic.TextModel is always available as poem.text.

Installation

1. Install espeak

Install espeak, free TTS software, to 'sound out' unknown words. See here for all downloads.

2. Install Poesy

pip install poesy

Or the development version:

pip install -U git+https://github.com/quadrismegistus/poesy

Usage

Create a poem: poem = Poem()

from poesy import Poem

# create a Poem object by string
poem = Poem("""
When in the chronicle of wasted time
I see descriptions of the fairest wights,
And beauty making beautiful old rhyme
In praise of ladies dead and lovely knights,
Then, in the blazon of sweet beauty's best,
Of hand, of foot, of lip, of eye, of brow,
I see their antique pen would have express'd
Even such a beauty as you master now.
So all their praises are but prophecies
Of this our time, all you prefiguring;
And, for they look'd but with divining eyes,
They had not skill enough your worth to sing:
For we, which now behold these present days,
Had eyes to wonder, but lack tongues to praise.
""")

# or create a Poem object by pointing to a text file
la_belle_dame = Poem(fn='poems/keats.la_belle_dame_sans_merci.txt')

Summary of annotations: poem.summary()

A quick tabular summary of most of the annotations Poesy has made on the poem.

  (#s,#l)  parse                                             rhyme      #feet    #syll    #parse
---------  ------------------------------------------------  -------  -------  -------  --------
     1.1   when|IN|the|CHRO|ni|CLE*|of|WA|sted|TIME          a              5       10         1
     1.2   i|SEE|de|SCRIP|tions|OF*|the|FAI|rest|WIGHTS      b              5       10         1
     1.3   and|BEAU|ty|MA|king|BEAU|ti|FUL*|old*|RHYME       a              5       10         3
     1.4   in|PRAISE|of|LA|dies|DEAD|and|LOVE|ly|KNIGHTS     b              5       10         1
     1.5   then|IN|the|BLA|zon|OF*|sweet*|BEAU|ty's|BEST     -              5       10         4
     1.6   of|HAND|of|FOOT|of|LIP|of|EYE|of|BROW             c              5       10         1
     1.7   i|SEE|their.an*|TIQUE.PEN*|would|HAVE|e|XPRESS'D  -              4       10         6
     1.8   E|ven|SUCH*|a|BEAU|ty|AS*|you|MA|ster|NOW         c              6       11         2
     1.9   so|ALL|their|PRAI|ses|ARE*|but|PRO|phe.cies*      -              4       10         3
     1.1   of|THIS*|our|TIME|all|YOU*|pre|FI|gu.ring*        d              4       10         6
     1.11  and|FOR*|they|LOOK'D|but|WITH*|di|VI|ning|EYES    e              5       10         2
     1.12  they|HAD|not|SKILL|e|NOUGH|your|WORTH|to|SING     d              5       10         1
     1.13  for|WE*|which|NOW|be|HOLD|these|PRE|sent|DAYS     e              5       10         2
     1.14  had|EYES|to|WON|der|BUT*|lack*|TONGUES|to|PRAISE  e              5       10         3


estimated schema
----------
meter: Iambic
feet: Pentameter
syllables: 10
rhyme: Sonnet A (abab cdcd eefeff)

Statistics on annotations: poem.statd

This dictionary combines the following dictionaries.

1. Estimated line scheme (in feet): poem.schemed_beat

{'scheme': (5,),
 'scheme_diff': 8,
 'scheme_length': 1,
 'scheme_repr': 'Pentameter',
 'scheme_type': 'Invariable'}

2. Estimated line scheme (in syllables): poem.schemed_syll

{'scheme': (10,),
 'scheme_diff': 1,
 'scheme_length': 1,
 'scheme_repr': 10,
 'scheme_type': 'Invariable'}

3. Estimated metrical scheme: poem.meterd

{'ambiguity': 2.0937047867021317,
 'constraint_TOTAL': 0.14598540145985403,
 'constraint_s_unstress': 0.0948905109489051,
 'constraint_unres_across': 0.014598540145985401,
 'constraint_unres_within': 0.014598540145985401,
 'constraint_w_stress': 0.021897810218978103,
 'length_avg_line': 10.071428571428571,
 'length_avg_parse': 10.071428571428571,
 'mpos_s': 0.48905109489051096,
 'mpos_ss': 0.0072992700729927005,
 'mpos_w': 0.48175182481751827,
 'mpos_ww': 0.021897810218978103,
 'perc_lines_ending_s': 0.8571428571428571,
 'perc_lines_ending_w': 0.14285714285714285,
 'perc_lines_fourthpos_s': 0.8571428571428571,
 'perc_lines_fourthpos_w': 0.14285714285714285,
 'perc_lines_starting_s': 0.07142857142857142,
 'perc_lines_starting_w': 0.9285714285714286,
 'type_foot': 'binary',
 'type_head': 'final',
 'type_scheme': 'iambic'}

Note: as of 0.4, the constraint_* keys use prosodic v3's constraint names, which differ from prosodic v1's (e.g. s_unstress rather than stress_s=>-u).

4. Estimated rhyme scheme: poem.rhymed

{'rhyme_scheme': ('Sonnet A', 'abab cdcd eefeff'),
 'rhyme_scheme_accuracy': 0.7,
 'rhyme_scheme_form': 'abab cdcd eefeff',
 'rhyme_scheme_name': 'Sonnet A',
 'rhyme_schemes': [(('Sonnet A', 'abab cdcd eefeff'), 0.7),
                   (('Sonnet, Shakespearean', 'abab cdcd efefgg'),
                    0.5555555555555556),
                   (('Sonnet E', 'abab cbcd cdedee'), 0.42857142857142855),
                   (('Sonnet B', 'abab cdcd effegg'), 0.4),
                   (('Sonnet D', 'ababbcdc ceceff'), 0.35714285714285715)]}

Iterate over lines: poem.lined

Every poem has a number of dictionaries, each keyed to a "line ID", a tuple of (linenum, stanzanum).

# The dictionary storing the string representation for the line:
for lineid,line_str in sorted(poem.lined.items()):
    print(lineid,line_str)

# Use this dictionary to loop over prosodic's Line objects instead
# (as of 0.4 these are prosodic v3 Line objects)
for lineid,line_obj in sorted(poem.prosodic.items()):
    print(lineid,line_obj.best_parse)

# Other dictionaries
poem.linenums              # lineid -> line number within poem
poem.linenums_bystanza     # lineid -> line number within stanza
poem.stanzanums            # lineid -> stanza number
poem.linelengths           # lineid -> length of line (in syllables)
poem.linelengths_bybeat    # lineid -> length of line (in feet)
poem.numparses             # lineid -> number of plausible parses for line
poem.rhymes                # lineid -> rhyme scheme symbol

Configure

Poesy depends on Prosodic (v3) for metrical parsing.

Prosodic v3 no longer uses named meter-config files (a v1 feature); meters are configured by keyword arguments instead (see prosodic.Meter). Pass a dict of meter kwargs to a Poem object or its parse method:

from poesy import Poem
poem = Poem(fn='poems/shakespeare_sonnets/sonnet-001.txt',
            meter=dict(max_s=2, max_w=2))

Or:

poem.parse(max_s=2, max_w=2)

Passing a v1 meter name string (e.g. meter='iambic_pentameter') emits a warning and falls back to prosodic's default meter.

Migrating to prosodic v3

Everything poesy computes is available directly in prosodic v3:

poesy prosodic v3
poem.summary() text.summary()
poem.statd['meter_type_scheme'] text.meter_type['type']
poem.schemed_beat text.line_scheme
poem.schemed_syll text.syllable_scheme
poem.rhymed text.rhyme_scheme
poem.rime_ids text.rhyme_ids
poem.isSonnet text.is_sonnet
poem.isShakespeareanSonnet text.is_shakespearean_sonnet

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

poesy-0.4.0.tar.gz (29.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

poesy-0.4.0-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

Details for the file poesy-0.4.0.tar.gz.

File metadata

  • Download URL: poesy-0.4.0.tar.gz
  • Upload date:
  • Size: 29.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for poesy-0.4.0.tar.gz
Algorithm Hash digest
SHA256 fe74ce4c9d985cccad678675e0da29b6bf0e61355b82fa271971058654439792
MD5 d76b20589e658a00db2011cdde98b4f8
BLAKE2b-256 188a648bfb34ed99c55b2c5609ec7a923ce26edfc6ba5152ffd2bed8c98ce3ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for poesy-0.4.0.tar.gz:

Publisher: release.yml on quadrismegistus/poesy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file poesy-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: poesy-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 24.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for poesy-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fb29fd5f4e321c22baa0007064ed9c5daa8103697430168767980e42cd945ce4
MD5 d9d97469ef90becde151eeec0a374dc1
BLAKE2b-256 63a8c7e27a3813eaeecb8cfcf268a8e7df94e39c8b99d9264fb95dba77082f2c

See more details on using hashes here.

Provenance

The following attestation bundles were made for poesy-0.4.0-py3-none-any.whl:

Publisher: release.yml on quadrismegistus/poesy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page