mirror of
https://github.com/Hopiu/python-markdown-oembed.git
synced 2026-03-16 22:10:24 +00:00
Merge pull request #1 from durgaBahadur/master
use flit packaging tool, write simple test
This commit is contained in:
commit
6df30f7cf3
15 changed files with 195 additions and 209 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -2,7 +2,10 @@
|
||||||
.idea
|
.idea
|
||||||
/dist
|
/dist
|
||||||
/.eggs
|
/.eggs
|
||||||
/venv
|
venv
|
||||||
*.pyc
|
*.pyc
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
*.coverage
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
|
||||||
13
README.md
Normal file
13
README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Python Markdown Plugin for oEmbed
|
||||||
|
|
||||||
|
## Install flit
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install flit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build needed packages for project
|
||||||
|
|
||||||
|
```
|
||||||
|
flit install
|
||||||
|
```
|
||||||
27
flake.lock
Normal file
27
flake.lock
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1698611440,
|
||||||
|
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
29
flake.nix
Normal file
29
flake.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
description = "Oembed plugin flake";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
|
||||||
|
};
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [];
|
||||||
|
};
|
||||||
|
pythonPackages = pkgs.python3Packages;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
in rec {
|
||||||
|
devShell.x86_64-linux = pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.python3
|
||||||
|
pkgs.python3Packages.pip
|
||||||
|
];
|
||||||
|
shellHook = ''
|
||||||
|
export PS1='\u@md-oembed \$ '
|
||||||
|
export PIP_PREFIX=$(pwd)/venv/pip_packages
|
||||||
|
export PYTHONPATH="$PIP_PREFIX/${pkgs.python3.sitePackages}:$PYTHONPATH"
|
||||||
|
export PATH="$PIP_PREFIX/bin:$PATH"
|
||||||
|
unset SOURCE_DATE_EPOCH
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from mdx_oembed.extension import OEmbedExtension
|
|
||||||
|
|
||||||
|
|
||||||
VERSION = '0.2.1'
|
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(**kwargs):
|
|
||||||
return OEmbedExtension(**kwargs)
|
|
||||||
46
pyproject.toml
Normal file
46
pyproject.toml
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
[build-system]
|
||||||
|
build-backend = "flit_core.buildapi"
|
||||||
|
requires = ["flit_core >=3.8.0,<4"]
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "python_markdown-oembed_extension"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = [
|
||||||
|
{name = "nmc", email = "contact-nmc@unibas.ch"},
|
||||||
|
]
|
||||||
|
description = "Detect inline pattern starting with '![', use the following data to request oembed data from the video hoster and create appropriate iframe html"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.7"
|
||||||
|
keywords = ["markdown", "html", "oembed"]
|
||||||
|
license = {text = "GPLv3"}
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"python-oembed",
|
||||||
|
"markdown",
|
||||||
|
"requests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"pylint ~=2.14.0",
|
||||||
|
"toml ~=0.10.2",
|
||||||
|
"yapf ~=0.32.0",
|
||||||
|
]
|
||||||
|
test = [
|
||||||
|
"pytest-cov ~=3.0.0",
|
||||||
|
"requests_mock",
|
||||||
|
"pyyaml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
my-script = "my_package.module:function"
|
||||||
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
source = ["src"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
addopts = "--cov --cov-report html --cov-report term-missing --cov-fail-under 15"
|
||||||
|
# ... other project metadata fields as specified in:
|
||||||
|
# https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import oembed
|
import oembed
|
||||||
|
|
||||||
YOUTUBE = oembed.OEmbedEndpoint('https://www.youtube.com/oembed', [
|
YOUTUBE = oembed.OEmbedEndpoint('https://www.youtube.com/oembed', [
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import logging
|
import logging
|
||||||
from markdown.inlinepatterns import Pattern
|
from markdown.inlinepatterns import Pattern
|
||||||
import oembed
|
import oembed
|
||||||
|
|
@ -10,7 +9,6 @@ LOG = logging.getLogger(__name__)
|
||||||
OEMBED_LINK_RE = r'\!\[([^\]]*)\]\(((?:https?:)?//[^\)]*)' \
|
OEMBED_LINK_RE = r'\!\[([^\]]*)\]\(((?:https?:)?//[^\)]*)' \
|
||||||
r'(?<!png)(?<!jpg)(?<!jpeg)(?<!gif)(?<!avif)(?<!webp)\)'
|
r'(?<!png)(?<!jpg)(?<!jpeg)(?<!gif)(?<!avif)(?<!webp)\)'
|
||||||
|
|
||||||
|
|
||||||
class OEmbedLinkPattern(Pattern):
|
class OEmbedLinkPattern(Pattern):
|
||||||
|
|
||||||
def __init__(self, pattern, md=None, oembed_consumer=None):
|
def __init__(self, pattern, md=None, oembed_consumer=None):
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from markdown import Extension
|
from markdown import Extension
|
||||||
import oembed
|
import oembed
|
||||||
from mdx_oembed.endpoints import DEFAULT_ENDPOINTS
|
from python_markdown_oembed_extension.endpoints import DEFAULT_ENDPOINTS
|
||||||
from mdx_oembed.inlinepatterns import OEmbedLinkPattern, OEMBED_LINK_RE
|
from python_markdown_oembed_extension.inlinepatterns import OEmbedLinkPattern, OEMBED_LINK_RE
|
||||||
|
|
||||||
|
|
||||||
class OEmbedExtension(Extension):
|
class OEmbedExtension(Extension):
|
||||||
|
|
@ -28,7 +27,8 @@ class OEmbedExtension(Extension):
|
||||||
consumer = oembed.OEmbedConsumer()
|
consumer = oembed.OEmbedConsumer()
|
||||||
|
|
||||||
if allowed_endpoints:
|
if allowed_endpoints:
|
||||||
for endpoint in allowed_endpoints:
|
for endpoint in allowed_endpoints:
|
||||||
consumer.addEndpoint(endpoint)
|
consumer.addEndpoint(endpoint)
|
||||||
|
|
||||||
return consumer
|
return consumer
|
||||||
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<p>In this video Jakob Zinsstag introduces the topic of the course. You will
|
||||||
|
discover that the relationship between humans and animals is manifold.
|
||||||
|
{.lead}</p>
|
||||||
|
<p><figure class="oembed ratio ratio-16x9"><iframe src="https://player.vimeo.com/video/734276368?h=f29c542352&app_id=122963" width="426" height="240" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" title="One-Health_Tales_EN_1-02"></iframe></figure> </p>
|
||||||
|
<p>Have a look at the farm of Jakob Zinsstag’s cousin in the Canton of Jura,
|
||||||
|
Switzerland. Different animals create different feelings: there are those we
|
||||||
|
love, some provoke fears and others will be eaten. Jakob Zinsstag shares the
|
||||||
|
personal experiences he has had with animals. </p>
|
||||||
|
<p><strong>How do you categorise your own experience with animals?</strong></p>
|
||||||
12
src/python_markdown_oembed_extension/tests/test_markdown.md
Normal file
12
src/python_markdown_oembed_extension/tests/test_markdown.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
In this video Jakob Zinsstag introduces the topic of the course. You will
|
||||||
|
discover that the relationship between humans and animals is manifold.
|
||||||
|
{.lead}
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Have a look at the farm of Jakob Zinsstag’s cousin in the Canton of Jura,
|
||||||
|
Switzerland. Different animals create different feelings: there are those we
|
||||||
|
love, some provoke fears and others will be eaten. Jakob Zinsstag shares the
|
||||||
|
personal experiences he has had with animals.
|
||||||
|
|
||||||
|
**How do you categorise your own experience with animals?**
|
||||||
21
src/python_markdown_oembed_extension/tests/test_markdown.py
Normal file
21
src/python_markdown_oembed_extension/tests/test_markdown.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import markdown, yaml, requests_mock
|
||||||
|
from python_markdown_oembed_extension.oembedextension import OEmbedExtension
|
||||||
|
from python_markdown_oembed_extension.endpoints import VIMEO
|
||||||
|
|
||||||
|
|
||||||
|
def test_full():
|
||||||
|
with ( requests_mock.Mocker() as m
|
||||||
|
, open('./src/python_markdown_oembed_extension/tests/vimeoMock.yaml', 'r') as vm
|
||||||
|
, open('./src/python_markdown_oembed_extension/tests/test_markdown.md', 'r') as md
|
||||||
|
, open('./src/python_markdown_oembed_extension/tests/test_expectedHtml.html', 'r') as expectedHtml
|
||||||
|
):
|
||||||
|
|
||||||
|
yml = yaml.safe_load(vm)
|
||||||
|
m.get(yml['request'], json=yml['response'])
|
||||||
|
|
||||||
|
mdString = md.read()
|
||||||
|
htmlString = markdown.markdown(mdString, extensions=[OEmbedExtension()])
|
||||||
|
print(htmlString)
|
||||||
|
|
||||||
|
assert htmlString == expectedHtml.read().rstrip()
|
||||||
|
|
||||||
30
src/python_markdown_oembed_extension/tests/vimeoMock.yaml
Normal file
30
src/python_markdown_oembed_extension/tests/vimeoMock.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
request: 'https://vimeo.com/734276368/f29c542352'
|
||||||
|
response:
|
||||||
|
account_type: 'live_premium'
|
||||||
|
author_name: 'NMC Universität Basel'
|
||||||
|
author_url: 'https://vimeo.com/newmediacenterunibasel'
|
||||||
|
description: ''
|
||||||
|
duration: 282
|
||||||
|
height: 240
|
||||||
|
html: >-
|
||||||
|
<iframe
|
||||||
|
src="https://player.vimeo.com/video/734276368?h=f29c542352&app_id=122963"
|
||||||
|
width="426" height="240" frameborder="0" allow="autoplay; fullscreen; picture-in-picture"
|
||||||
|
title="One-Health_Tales_EN_1-02"
|
||||||
|
>
|
||||||
|
</iframe>
|
||||||
|
is_plus: '0'
|
||||||
|
provider_name: 'Vimeo'
|
||||||
|
provider_url: 'https://vimeo.com/'
|
||||||
|
thumbnail_height: 166
|
||||||
|
thumbnail_url: 'https://i.vimeocdn.com/video/1480489232-5ca2d723cadc09ae077c8b437581e84bd0485049780c60e218986fda60881110-d_295x166'
|
||||||
|
thumbnail_url_with_play_button: 'https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1480489232-5ca2d723cadc09ae077c8b437581e84bd0485049780c60e218986fda60881110-d_295x166&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png'
|
||||||
|
thumbnail_width: 295
|
||||||
|
title: 'One-Health_Tales_EN_1-02'
|
||||||
|
type: 'video'
|
||||||
|
upload_date: '2022-07-28 04:16:03'
|
||||||
|
uri: '/videos/734276368:f29c542352'
|
||||||
|
version: '1.0'
|
||||||
|
video_id: 734276368
|
||||||
|
width: 426
|
||||||
192
tests.py
192
tests.py
|
|
@ -1,192 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
|
||||||
import unittest
|
|
||||||
import markdown
|
|
||||||
from mock import patch
|
|
||||||
from nose.plugins.skip import SkipTest
|
|
||||||
from mdx_oembed.extension import OEMBED_LINK_RE
|
|
||||||
from mdx_oembed import endpoints
|
|
||||||
|
|
||||||
|
|
||||||
class OEmbedPatternRegexTestCase(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.re = re.compile(OEMBED_LINK_RE)
|
|
||||||
|
|
||||||
def test_ignore_relative_image_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNone(match)
|
|
||||||
|
|
||||||
def test_ignore_absolute_image_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNone(match)
|
|
||||||
|
|
||||||
def test_ignore_png_image_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNone(match)
|
|
||||||
|
|
||||||
def test_ignore_jpg_image_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNone(match)
|
|
||||||
|
|
||||||
def test_ignore_gif_image_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNone(match)
|
|
||||||
|
|
||||||
def test_find_youtube_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNotNone(match)
|
|
||||||
|
|
||||||
def test_find_youtube_short_link(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNotNone(match)
|
|
||||||
|
|
||||||
def test_find_youtube_http(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNotNone(match)
|
|
||||||
|
|
||||||
def test_find_youtube_https(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNotNone(match)
|
|
||||||
|
|
||||||
def test_find_youtube_auto(self):
|
|
||||||
text = ''
|
|
||||||
match = self.re.match(text)
|
|
||||||
self.assertIsNotNone(match)
|
|
||||||
|
|
||||||
|
|
||||||
class OEmbedExtensionTestCase(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.markdown = markdown.Markdown(extensions=['oembed'])
|
|
||||||
|
|
||||||
def assert_convert(self, text, expected):
|
|
||||||
with patch('oembed.OEmbedEndpoint') as MockOEmbedEndpoint:
|
|
||||||
MockOEmbedEndpoint.get.return_value = expected
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertEqual(output, expected)
|
|
||||||
|
|
||||||
|
|
||||||
class IgnoredTestCase(OEmbedExtensionTestCase):
|
|
||||||
"""
|
|
||||||
The OEmbedExtension should ignore these tags allowing markdown's image
|
|
||||||
processor to find and handle them.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_relative(self):
|
|
||||||
text = ''
|
|
||||||
expected = '<p><img alt="alt" src="image.png" /></p>'
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertEqual(output, expected)
|
|
||||||
|
|
||||||
def test_slash_relative(self):
|
|
||||||
text = ''
|
|
||||||
expected = '<p><img alt="alt" src="/image.png" /></p>'
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertEqual(output, expected)
|
|
||||||
|
|
||||||
def test_absolute(self):
|
|
||||||
text = ''
|
|
||||||
expected = '<p><img alt="Mumbo Jumbo" src="http://tannern.com/mumbo-jumbo.jpg" /></p>'
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertEqual(output, expected)
|
|
||||||
|
|
||||||
|
|
||||||
class ProtocolVarietyTestCase(OEmbedExtensionTestCase):
|
|
||||||
|
|
||||||
def test_http(self):
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
def test_https(self):
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
def test_auto(self):
|
|
||||||
raise SkipTest()
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
|
|
||||||
class YoutubeTestCase(OEmbedExtensionTestCase):
|
|
||||||
"""
|
|
||||||
The OEmbedExtension should handle embedding for these cases.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_youtube_link(self):
|
|
||||||
"""
|
|
||||||
YouTube video link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
def test_youtube_short_link(self):
|
|
||||||
"""
|
|
||||||
Short format YouTube video link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
|
|
||||||
class VimeoTestCase(OEmbedExtensionTestCase):
|
|
||||||
|
|
||||||
def test_vimeo_link(self):
|
|
||||||
"""
|
|
||||||
Vimeo video link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
class SlideshareTestCase(OEmbedExtensionTestCase):
|
|
||||||
|
|
||||||
def test_slideshare_link(self):
|
|
||||||
"""
|
|
||||||
Slideshare Presentation link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
|
|
||||||
class LimitedOEmbedExtensionTestCase(OEmbedExtensionTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.markdown = markdown.Markdown(
|
|
||||||
extensions=['oembed'],
|
|
||||||
extension_configs={
|
|
||||||
'oembed': {
|
|
||||||
'allowed_endpoints': [endpoints.YOUTUBE],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
def test_youtube_link(self):
|
|
||||||
"""
|
|
||||||
YouTube video link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertIn('<iframe', output)
|
|
||||||
|
|
||||||
def test_vimeo_link(self):
|
|
||||||
"""
|
|
||||||
Vimeo video link.
|
|
||||||
"""
|
|
||||||
text = ''
|
|
||||||
output = self.markdown.convert(text)
|
|
||||||
self.assertNotIn('<iframe', output)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
Loading…
Reference in a new issue