summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVal Neekman <val@neekware.com>2012-10-14 18:49:13 -0700
committerVal Neekman <val@neekware.com>2012-10-14 18:49:13 -0700
commit64ffcbcedee3bead5e3a20cb1c545854b3bd651b (patch)
tree5b9fd44f1b7e55befc6df7321a092fdd212ebe61
parentbe60050791262776db3c59ff6c4bf7da7c2a1b43 (diff)
downloadpython-slugify-64ffcbcedee3bead5e3a20cb1c545854b3bd651b.tar.gz
Initial version
-rw-r--r--.gitignore5
-rw-r--r--.travis.yml8
-rw-r--r--README.md92
-rwxr-xr-xpep8.sh5
-rw-r--r--requirements.txt2
-rwxr-xr-xsetup.py83
-rw-r--r--slugify/__init__.py67
-rw-r--r--test.py29
8 files changed, 289 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..046cca1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.pyc
+MANIFEST
+dist/
+build/
+*.egg-info/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6990722
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+install:
+ - pip install -q -r requirements.txt --use-mirrors
+script: python test.py
+
diff --git a/README.md b/README.md
index 53eabe1..f25ae6f 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,90 @@
-python-slugify
-============== \ No newline at end of file
+Python Slugify
+====================
+
+**A Python slugify application that handles unicode**
+
+**Author:** Val Neekman [ info@neekware.com, @vneekman ]
+
+Overview
+========
+
+A Python slugify application that handles unicode.
+
+How to install
+==================
+
+ 1. easy_install python-slugify
+ 2. pip install python-slugify
+ 3. git clone http://github.com/un33k/python-slugify
+ a. cd python-slugify
+ b. run python setup.py
+ 4. wget https://github.com/un33k/python-slugify/zipball/master
+ a. unzip the downloaded file
+ b. cd into python-slugify-* directory
+ c. run python setup.py
+
+How to use
+=================
+ from slugify import slugify
+
+ s = "This is a test ---"
+ r = slugify(s)
+ self.assertEquals(r, "this-is-a-test")
+
+ s = 'C\'est déjà l\'été.'
+ r = slugify(s)
+ self.assertEquals(r, "c-est-deja-lete")
+
+ s = 'Nín hǎo. Wǒ shì zhōng guó rén'
+ r = slugify(s)
+ self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")
+
+ s = '影師嗎'
+ r = slugify(s)
+ self.assertEquals(r, "ying-shi-ma")
+
+
+Running the tests
+=================
+
+To run the tests against the current environment:
+
+ python test.py
+
+Changelog
+=========
+
+0.0.1
+-----
+
+* Initial release
+
+
+License
+=======
+
+Copyright © Neekware Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
diff --git a/pep8.sh b/pep8.sh
new file mode 100755
index 0000000..276f602
--- /dev/null
+++ b/pep8.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo -e "\nRunning: (pep8 --show-source --show-pep8 --select=errors --testsuite=.)\n\n"
+pep8 --show-source --show-pep8 --select=errors --testsuite=./
+echo -e "\n\n"
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..000ccb7
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+Unidecode>=0.04.9
+
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..e2df292
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+
+# -*- coding: utf-8 -*-
+from setuptools import setup
+import re
+import os
+import sys
+
+
+name = 'python-slugify'
+package = 'slugify'
+description = 'A Python slugify application that handles unicode'
+url = 'https://github.com/un33k/python-slugify'
+author = 'Val Neekman'
+author_email = 'info@neekware.com'
+license = 'BSD'
+install_requires = ['Unidecode>=0.04.9']
+classifiers = [
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: POSIX',
+ 'Programming Language :: Python',
+]
+
+
+def get_version(package):
+ """
+ Return package version as listed in `__version__` in `init.py`.
+ """
+ init_py = open(os.path.join(package, '__init__.py')).read()
+ return re.search("^__version__ = ['\"]([^'\"]+)['\"]", init_py, re.MULTILINE).group(1)
+
+
+def get_packages(package):
+ """
+ Return root package and all sub-packages.
+ """
+ return [dirpath
+ for dirpath, dirnames, filenames in os.walk(package)
+ if os.path.exists(os.path.join(dirpath, '__init__.py'))]
+
+
+def get_package_data(package):
+ """
+ Return all files under the root package, that are not in a
+ package themselves.
+ """
+ walk = [(dirpath.replace(package + os.sep, '', 1), filenames)
+ for dirpath, dirnames, filenames in os.walk(package)
+ if not os.path.exists(os.path.join(dirpath, '__init__.py'))]
+
+ filepaths = []
+ for base, filenames in walk:
+ filepaths.extend([os.path.join(base, filename)
+ for filename in filenames])
+ return {package: filepaths}
+
+
+if sys.argv[-1] == 'publish':
+ os.system("python setup.py sdist upload")
+ args = {'version': get_version(package)}
+ print "You probably want to also tag the version now:"
+ print " git tag -a %(version)s -m 'version %(version)s'" % args
+ print " git push --tags"
+ sys.exit()
+
+
+setup(
+ name=name,
+ version=get_version(package),
+ url=url,
+ license=license,
+ description=description,
+ author=author,
+ author_email=author_email,
+ packages=get_packages(package),
+ package_data=get_package_data(package),
+ install_requires=install_requires,
+ classifiers=classifiers
+)
+
+
diff --git a/slugify/__init__.py b/slugify/__init__.py
new file mode 100644
index 0000000..94d0bc1
--- /dev/null
+++ b/slugify/__init__.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+
+__version__ = '0.0.1'
+
+__all__ = ['slugify']
+
+import re
+import unicodedata
+from htmlentitydefs import name2codepoint
+from types import UnicodeType
+from unidecode import unidecode
+
+# character entity reference
+CHAR_ENTITY_REXP = re.compile('&(%s);' % '|'.join(name2codepoint))
+
+# decimal character reference
+DECIMAL_REXP = re.compile('&#(\d+);')
+
+# hexadecimal character reference
+HEX_REXP = re.compile('&#x([\da-fA-F]+);')
+
+REPLACE1_REXP = re.compile(r'[\']+')
+REPLACE2_REXP = re.compile(r'[^-a-z0-9]+')
+REMOVE_REXP = re.compile('-{2,}')
+
+def slugify(text, entities=True, decimal=True, hexadecimal=True):
+ """ Make a slug from the given text """
+
+ # text to unicode
+ if type(text) != UnicodeType:
+ text = unicode(text, 'utf-8', 'ignore')
+
+ # decode unicode ( 影師嗎 = Ying Shi Ma)
+ text = unidecode(text)
+
+ # text back to unicode
+ text = unicode(text, 'utf-8', 'ignore')
+
+ # character entity reference
+ if entities:
+ text = CHAR_ENTITY_REXP.sub(lambda m: unichr(name2codepoint[m.group(1)]), text)
+
+ # decimal character reference
+ if decimal:
+ try:
+ text = DECIMAL_REXP.sub(lambda m: unichr(int(m.group(1))), text)
+ except:
+ pass
+
+ # hexadecimal character reference
+ if hexadecimal:
+ try:
+ text = HEX_REXP.sub(lambda m: unichr(int(m.group(1), 16)), text)
+ except:
+ pass
+
+ # translate
+ text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore')
+
+ # replace unwanted characters
+ text = REPLACE1_REXP.sub('', text.lower()) # replace ' with nothing instead with -
+ text = REPLACE2_REXP.sub('-', text.lower())
+
+ # remove redundant -
+ text = REMOVE_REXP.sub('-', text).strip('-')
+
+ return text
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..d713ee3
--- /dev/null
+++ b/test.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+from slugify import slugify
+
+class TestSequenceFunctions(unittest.TestCase):
+
+ def test_space_dash(self):
+ txt = "This is a test ---"
+ r = slugify(txt)
+ self.assertEquals(r, "this-is-a-test")
+
+ def test_special_chars(self):
+ txt = 'C\'est déjà l\'été.'
+ r = slugify(txt)
+ self.assertEquals(r, "cest-deja-lete")
+
+ txt = 'Nín hǎo. Wǒ shì zhōng guó rén'
+ r = slugify(txt)
+ self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")
+
+ txt = '影師嗎'
+ r = slugify(txt)
+ self.assertEquals(r, "ying-shi-ma")
+
+if __name__ == '__main__':
+ unittest.main()
+
+