Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

Commit

Permalink
Merge 9ffff92 into 5958eb1
Browse files Browse the repository at this point in the history
  • Loading branch information
cmccandless committed Dec 15, 2017
2 parents 5958eb1 + 9ffff92 commit b552c29
Show file tree
Hide file tree
Showing 31 changed files with 516 additions and 68 deletions.
5 changes: 5 additions & 0 deletions .coveragerc
@@ -0,0 +1,5 @@
[report]
omit =
*/python?.?/*
*__init__*
tests/*
2 changes: 2 additions & 0 deletions .coveralls.yml
@@ -0,0 +1,2 @@
service_name: travis-ci
repo_token: d9edOeB1k2fIKJMosheHF3jpxYJxxpuid
2 changes: 2 additions & 0 deletions .flake8
@@ -0,0 +1,2 @@
[flake8]
exclude = __init__.py, docs/, build/, setup.py
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -89,3 +89,5 @@ ENV/
# Rope project settings
.ropeproject
MANIFEST

.vscode
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -23,3 +23,6 @@ before_script:

script:
- make test

after_success:
- coveralls
5 changes: 3 additions & 2 deletions Makefile
Expand Up @@ -2,7 +2,8 @@ init:
pip install -r requirements.txt

lint:
flake8 --exclude __init__.py markdown_generator
flake8

test:
nosetests
python -m pytest
coverage run -m pytest -v
2 changes: 1 addition & 1 deletion README.md
@@ -1,9 +1,9 @@
[![Build Status](https://travis-ci.org/cmccandless/markdown-generator.svg?branch=master)](https://travis-ci.org/cmccandless/markdown-generator)
[![Coverage Status](https://coveralls.io/repos/github/cmccandless/markdown-generator/badge.svg?branch=master)](https://coveralls.io/github/cmccandless/markdown-generator?branch=master)

Markdown Generator
========================

Python module for generator GitHub-flavored markdown

pip install markdown-generator

2 changes: 1 addition & 1 deletion example.md
Expand Up @@ -41,7 +41,7 @@ writelines()2
![my alt text](https://example.com/link/to/image.png)

```Python
s = 'Python syntax highlighting
s = 'Python syntax highlighting'
print(s)
```
| col1 | col2 | col3 |
Expand Down
4 changes: 2 additions & 2 deletions example.py
Expand Up @@ -46,13 +46,13 @@
writer.writeline(image)

code = mg.Code('Python')
code.append("s = 'Python syntax highlighting")
code.append("s = 'Python syntax highlighting'")
code.append("print(s)")
writer.write(code)

table = mg.Table()
table.add_column('col1')
table.add_column('col2', mg.alignment.CENTER)
table.add_column('col2', mg.Alignment.CENTER)
table.add_column('col3', 2)
for i in range(3):
table.append(*['e{}f{}'.format(i, j) for j in range(3)])
Expand Down
3 changes: 2 additions & 1 deletion markdown_generator/__init__.py
Expand Up @@ -2,7 +2,8 @@
from .code import Code
from .emphasis import (emphasis, strong, strikethrough)
from .image import Image
from .link import link
from .mdlink import link
from .list import (List, CheckList)
from .table import Table
from .writer import Writer
from .alignment import Alignment
25 changes: 5 additions & 20 deletions markdown_generator/alignment.py
@@ -1,22 +1,7 @@
class ColumnAlignment(object):
def __init__(self, value):
self.value = value
from enum import IntEnum

def has_flag(self, flag):
if isinstance(flag, ColumnAlignment):
return self.value & flag.value > 0
elif isinstance(flag, int):
return self.value & flag > 0
return False

def __eq__(self, other):
if isinstance(other, ColumnAlignment):
return self.value == other.value
elif isinstance(other, int):
return self.value == other
return False


LEFT = ColumnAlignment(1)
RIGHT = ColumnAlignment(2)
CENTER = ColumnAlignment(3)
class Alignment(IntEnum):
LEFT = 1
RIGHT = 2
CENTER = 3
2 changes: 2 additions & 0 deletions markdown_generator/blockquote.py
Expand Up @@ -7,6 +7,8 @@ def append(self, text):
self.lines.append(text)

def __str__(self):
if not self.lines:
return ''
lines = ['{} {}\n'.format(''.ljust(self.level, '>'), line)
for line in self.lines]
return ''.join(lines) + '\n'
15 changes: 9 additions & 6 deletions markdown_generator/code.py
Expand Up @@ -7,9 +7,12 @@ def append(self, text):
self.lines.append(text)

def __str__(self):
lang = '' if self.language is None else self.language
lines = []
lines.append('```{}'.format(lang))
lines.extend(self.lines)
lines.append('```')
return '\n'.join(lines) + '\n'
if self.lines:
lang = '' if self.language is None else self.language
lines = []
lines.append('```{}'.format(lang))
lines.extend(self.lines)
lines.append('```')
return '\n'.join(lines) + '\n'
else:
return ''
2 changes: 1 addition & 1 deletion markdown_generator/emphasis.py
@@ -1,5 +1,5 @@
def wrap(text, tag):
return tag + str(text) + tag
return tag + str(text) + tag if text else ''


def emphasis(text):
Expand Down
2 changes: 2 additions & 0 deletions markdown_generator/image.py
Expand Up @@ -4,6 +4,8 @@ def __init__(self, img_url, alt_text=None):
self.alt_text = alt_text

def __str__(self):
if not self.img_url:
return ''
return '![{}]({})'.format(('' if self.alt_text is None
else self.alt_text),
self.img_url)
2 changes: 0 additions & 2 deletions markdown_generator/link.py

This file was deleted.

25 changes: 17 additions & 8 deletions markdown_generator/list.py
Expand Up @@ -7,9 +7,16 @@ def append(self, item):
self.items.append(item)

def __str__(self):
marker = '1.' if self.ordered else '*'
result = ''.join('{} {}\n'.format(marker, item) for item in self.items)
return result + '\n'
if self.items:
def prepend(item, marker):
return '{} {}\n'.format(marker, item)
if self.ordered:
result = ''.join(prepend(x, '{}.'.format(i + 1))
for i, x in enumerate(self.items))
else:
result = ''.join(prepend(x, '*') for x in self.items)
return result + '\n'
return ''


class CheckList(object):
Expand All @@ -20,8 +27,10 @@ def append(self, item, done=False):
self.items.append((item, done))

def __str__(self):
lines = []
for item, done in self.items:
mark = 'x' if done else ' '
lines.append('- [{}] {}\n'.format(mark, item))
return ''.join(lines) + '\n'
if self.items:
lines = []
for item, done in self.items:
mark = 'x' if done else ' '
lines.append('- [{}] {}\n'.format(mark, item))
return ''.join(lines) + '\n'
return ''
6 changes: 6 additions & 0 deletions markdown_generator/mdlink.py
@@ -0,0 +1,6 @@
def link(url, text=None):
if url:
if text:
return '[{}]({})'.format(text, url)
return url
return ''
36 changes: 19 additions & 17 deletions markdown_generator/table.py
@@ -1,16 +1,14 @@
from .alignment import LEFT, RIGHT, CENTER, ColumnAlignment
from .alignment import Alignment


class Table(object):
def __init__(self):
self.columns = []
self.entries = []

def add_column(self, heading, alignment=LEFT):
def add_column(self, heading, alignment=Alignment.LEFT):
if isinstance(alignment, int):
alignment = ColumnAlignment(alignment)
if alignment not in [LEFT, CENTER, RIGHT]:
raise ValueError('Table.addColumn(): invalid alignment given')
alignment = Alignment(alignment)
self.columns.append(Column(heading, alignment))

def append(self, *fields):
Expand All @@ -23,20 +21,24 @@ def format_row(self, fields):
return ' | '.join([''] + [str(f) for f in fields] + ['']).strip()

def __str__(self):
titleRow = '|'
separatorRow = '|'
for column in self.columns:
titleRow += ' {} |'.format(column.heading)
separatorRow += '{}---{}|'.format(
':' if column.alignment.has_flag(LEFT) else ' ',
':' if column.alignment.has_flag(RIGHT) else ' '
)
result = '{}\n{}\n'.format(titleRow, separatorRow)
result += '\n'.join(map(self.format_row, self.entries))
return result + '\n'
if self.columns:
titleRow = '|'
separatorRow = '|'
for column in self.columns:
titleRow += ' {} |'.format(column.heading)
separatorRow += '{}---{}|'.format(
':' if bool(Alignment.LEFT & column.alignment) else ' ',
':' if bool(Alignment.RIGHT & column.alignment) else ' '
)
result = '{}\n{}\n'.format(titleRow, separatorRow)
result += '\n'.join(map(self.format_row, self.entries))
if self.entries:
result += '\n'
return result + '\n'
return ''


class Column(object):
def __init__(self, heading, alignment=LEFT):
def __init__(self, heading, alignment=Alignment.LEFT):
self.heading = heading
self.alignment = alignment
3 changes: 2 additions & 1 deletion requirements.txt
@@ -1,4 +1,5 @@
flake8==3.5.0
pep8>1.7,<1.7.99
pyflakes==1.6.0
nose==1.3.7
ddt==1.1.1
coveralls>=1.2.0
6 changes: 6 additions & 0 deletions tests/helper.py
@@ -0,0 +1,6 @@
import unittest


class MarkdownTestCase(unittest.TestCase):
def assertRenderedEqual(self, obj, expected):
return self.assertEqual(str(obj), expected)
19 changes: 19 additions & 0 deletions tests/test_alignment.py
@@ -0,0 +1,19 @@
import unittest

from markdown_generator import Alignment


class AlignmentTest(unittest.TestCase):
def test_alignment_none(self):
with self.assertRaises(ValueError):
Alignment(None)

def test_alignment_from_value(self):
self.assertEqual(Alignment(1), 1)

def test_invalid_alignment(self):
with self.assertRaises(ValueError):
Alignment(999)

def test_left_or_right_is_center(self):
self.assertEqual(Alignment.LEFT | Alignment.RIGHT, Alignment.CENTER)
44 changes: 44 additions & 0 deletions tests/test_blockquote.py
@@ -0,0 +1,44 @@
from .helper import MarkdownTestCase

from markdown_generator import BlockQuote


class TestBlockQuote(MarkdownTestCase):
def assertRenderedEqual(self, bq, expected):
self.assertEqual(str(bq), expected)

def test_empty(self):
self.assertRenderedEqual(BlockQuote(), '')

def test_single_line(self):
bq = BlockQuote()
bq.append('My quote here')
self.assertRenderedEqual(bq, '> My quote here\n\n')

def test_multiple_lines(self):
bq = BlockQuote()
bq.append('My quote here')
bq.append('Longer quote')
bq.append('Even longer')
expected = ('> My quote here\n'
'> Longer quote\n'
'> Even longer\n\n')
self.assertRenderedEqual(bq, expected)

def test_level_other_than_one_empty(self):
self.assertRenderedEqual(BlockQuote(2), '')

def test_level_other_than_one_single_line(self):
bq = BlockQuote(3)
bq.append('My quote here')
self.assertRenderedEqual(bq, '>>> My quote here\n\n')

def test_level_other_than_one_multi_line(self):
bq = BlockQuote(2)
bq.append('My quote here')
bq.append('Longer quote')
bq.append('Even longer')
expected = ('>> My quote here\n'
'>> Longer quote\n'
'>> Even longer\n\n')
self.assertRenderedEqual(bq, expected)
40 changes: 40 additions & 0 deletions tests/test_code.py
@@ -0,0 +1,40 @@
from .helper import MarkdownTestCase

from markdown_generator import Code


class CodeTest(MarkdownTestCase):
def test_empty(self):
self.assertRenderedEqual(Code(), '')

def test_empty_with_language(self):
code = Code('Python')
self.assertRenderedEqual(code, '')

def test_single_line(self):
code = Code()
code.append('print("test")')
self.assertRenderedEqual(code, '```\nprint("test")\n```\n')

def test_single_line_with_language(self):
code = Code('Python')
code.append('print("test")')
self.assertRenderedEqual(code, '```Python\nprint("test")\n```\n')

def test_multiple_lines(self):
code = Code()
code.append('print("test")')
code.append('print("test2")')
self.assertRenderedEqual(
code,
'```\nprint("test")\nprint("test2")\n```\n'
)

def test_multiple_lines_with_language(self):
code = Code('Python')
code.append('print("test")')
code.append('print("test2")')
self.assertRenderedEqual(
code,
'```Python\nprint("test")\nprint("test2")\n```\n'
)

0 comments on commit b552c29

Please sign in to comment.