├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── materializecssform ├── __init__.py ├── config.py ├── meta.py ├── templates │ └── materializecssform │ │ ├── attrs.html │ │ ├── field.html │ │ ├── field_icon.html │ │ ├── form.html │ │ └── formset.html ├── templatetags │ ├── __init__.py │ └── materializecss.py └── tests.py ├── pyproject.toml ├── setup.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | README.rst 56 | venv 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Florent CLAPIÉ 4 | Copyright (c) 2020 Kal Walkden, Samuel von Stachelski 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include materializecssform *.html 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PyPI version](https://badge.fury.io/py/django-materializecss-form.svg)](https://pypi.org/project/django-materializecss-form/) 2 | 3 | # materialize-css-form 4 | Materializecss for Django Form 5 | 6 | A simple Django template tag to work with [Materializecss](http://materializecss.com/) 7 | 8 | ## Install 9 | 10 | From [PyPi](https://pypi.org/project/django-materializecss-form/): 11 | 12 | ``` 13 | pip install django-materializecss-form 14 | ``` 15 | 16 | From [GitHub](https://github.com/kalwalkden/django-materializecss-form) 17 | 18 | Add module to INSTALLED_APPS: 19 | 20 | ``` 21 | INSTALLED_APPS = ( 22 | 'materializecssform', 23 | ... 24 | ) 25 | ``` 26 | 27 | Add Materialize CSS to your project ([Official Documentation](https://materializecss.com/getting-started.html)): 28 | 29 | In your base.html: 30 | 31 | ``` 32 | 33 | 34 | {% block css %} 35 | 36 | 37 | {% endblock css %} 38 | 39 | 40 | ``` 41 | 42 | ``` 43 | 44 | 45 | 46 | {% block javascript %} 47 | 51 | 52 | 53 | 54 | 63 | {% endblock javascript %} 64 | 65 | ... 66 | 67 | 68 | ``` 69 | 70 | ## Usage 71 | 72 | Import the module simply like this: 73 | 74 | ```html 75 | {% load materializecss %} 76 | ``` 77 | 78 | ### Full form 79 | 80 | Format a whole form: 81 | 82 | ```html 83 | {{ form|materializecss }} 84 | ``` 85 | 86 | ### Individual field 87 | 88 | Format only a specific field: 89 | 90 | ```html 91 | {{ form.|materializecss }} 92 | ``` 93 | 94 | ### Custom size (default is 's12') 95 | 96 | Apply custom sizes in grid ([see Materialize CSS documentation](https://materializecss.com/grid.html)): 97 | ```html 98 | {{ form|materializecss:'m6' }} 99 | {{ form|materializecss:'custom_size=m6' }} 100 | ``` 101 | 102 | 103 | ### Icons support 104 | 105 | This is most useful for adding a descriptive icon when you are creating a custom layout by building the form one field at a time. Substitue FIELD_NAME below with one of the field names from your form. 106 | 107 | ```html 108 | {{ form.FIELD_NAME|materializecss:'s12 m6, icon=person' }} 109 | {{ form.FIELD_NAME|materializecss:'custom_size=s12 m6, icon=person' }} 110 | ``` 111 | 112 | #### Optional icon sets 113 | 114 | If you're using optional icon sets you need to set `MATERIALIZECSS_ICON_SET` in your settings file: 115 | 116 | ```python 117 | MATERIALIZECSS_ICON_SET = 'fontawesome' 118 | ``` 119 | 120 | Currently [Font Awesome](https://www.fontawesome.com/) and [GLYPHICONS](https://www.glyphicons.com) is supported, however you might need to modify your CSS for full support. 121 | 122 | ### Note about `DateTimeField` 123 | Input field is rendered as a *datetime-local* type, this lets the user easily enter both a date and a time. As this field requires ISO-8601 format, your main project settings need to include the ISO format in order for the form to interpret this field valid: 124 | ``` 125 | from django.conf.global_settings import DATETIME_INPUT_FORMATS 126 | 127 | # ISO 8601 datetime format to accept html5 datetime input values 128 | DATETIME_INPUT_FORMATS += ["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M"] 129 | ``` 130 | 131 | ## Demo 132 | 133 | ![Basic form](https://cloud.githubusercontent.com/assets/3958123/6165004/a1984f52-b2a4-11e4-8ae2-078505991b0d.png) 134 | 135 | ![DatePicker](https://cloud.githubusercontent.com/assets/3958123/6165005/a19bf044-b2a4-11e4-9989-6a64f9c97087.png) 136 | 137 | ![DateTimePicker](https://user-images.githubusercontent.com/556361/49763533-8a44f580-fc92-11e8-8d24-f45373becd11.png) 138 | 139 | ## Help 140 | 141 | ### Widget 142 | 143 | - TextInput 144 | - Textarea 145 | - CheckboxInput 146 | - RadioSelect 147 | - Select 148 | - SelectMultiple 149 | - CheckboxSelectMultiple 150 | - Filefield 151 | - DateField 152 | - DateTimeField 153 | 154 | ## Inspired by 155 | 156 | [django-bootstrap-form](https://github.com/tzangms/django-bootstrap-form) 157 | 158 | ## Originally Built By 159 | 160 | Florent CLAPIÉ ([PyPI](https://pypi.org/user/florent1933/)) 161 | -------------------------------------------------------------------------------- /materializecssform/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kalwalkden/django-materializecss-form/2244174c5d56377704cab96ef4f7108484f86c3d/materializecssform/__init__.py -------------------------------------------------------------------------------- /materializecssform/config.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | MATERIALIZECSS_COLUMN_COUNT = getattr(settings, 'MATERIALIZECSS_COLUMN_COUNT', 12) 4 | MATERIALIZECSS_VALIDATION = getattr(settings, 'MATERIALIZECSS_VALIDATION', True) 5 | MATERIALIZECSS_ICON_SET = getattr(settings, 'MATERIALIZECSS_ICON_SET', 'default') 6 | -------------------------------------------------------------------------------- /materializecssform/meta.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.1.17" 2 | 3 | 4 | __version_info__ = VersionInfo._from_version_string(__version__) 5 | 6 | __title__ = "django-materializecss-form" 7 | __description__ = "A simple Django form template tag to work with Materializecss" 8 | __url__ = "https://github.com/kalwalkden/django-materializecss-form" 9 | __uri__ = "https://github.com/kalwalkden/django-materializecss-form" 10 | __doc__ = __description__ + " <" + __uri__ + ">" 11 | 12 | __author__ = "Kal Walkden, Samuel von Stachelski" 13 | __email__ = "kal@walkden.us, sam@basx.dev" 14 | 15 | __license__ = "MIT" 16 | __copyright__ = "Copyright (c) 2020 Kal Walkden" 17 | -------------------------------------------------------------------------------- /materializecssform/templates/materializecssform/attrs.html: -------------------------------------------------------------------------------- 1 | {% for name, value in field.field.widget.attrs.items %} 2 | {% if value is not False %} 3 | {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}" {% endif %} 4 | {% endif %} 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /materializecssform/templates/materializecssform/field.html: -------------------------------------------------------------------------------- 1 | {% load materializecss %} 2 | {% load l10n %} 3 | 4 | 5 | {% if field|is_checkbox %} 6 |
7 |
8 | {% if classes.icon %} 9 | {% include 'materializecssform/field_icon.html' %} 10 | {% endif %} 11 | 22 | {% if field.help_text %} 23 |

24 | {{ field.help_text|safe }} 25 |

26 | {% endif %} 27 |
28 |
29 | {% elif field|is_radio %} 30 |
31 |
32 | {% if classes.icon %} 33 | {% include 'materializecssform/field_icon.html' %} 34 | {% endif %} 35 | 44 | {% if field.help_text %} 45 |

46 | {{ field.help_text|safe }} 47 |

48 | {% endif %} 49 |
50 |
51 | {% elif field|is_date_input %} 52 |
53 | {% if classes.icon %} 54 | {% include 'materializecssform/field_icon.html' %} 55 | {% endif %} 56 | 57 | 58 | 59 | 60 | {% for error in field.errors %} 61 | {{ error }} 62 | {% endfor %} 63 | 64 | {% if field.help_text %} 65 |

66 | {{ field.help_text|safe }} 67 |

68 | {% endif %} 69 | 70 |
71 | {% elif field|is_datetime_input %} 72 |
73 | {% if classes.icon %} 74 | {% include 'materializecssform/field_icon.html' %} 75 | {% endif %} 76 | 77 | 78 | 79 | 80 | {% for error in field.errors %} 81 | {{ error }} 82 | {% endfor %} 83 | 84 | {% if field.help_text %} 85 |

86 | {{ field.help_text|safe }} 87 |

88 | {% endif %} 89 | 90 |
91 | {% elif field|is_select %} 92 |
93 | {% if field|is_select_multiple %} 94 | {% if classes.icon %} 95 | {% include 'materializecssform/field_icon.html' %} 96 | {% endif %} 97 | 102 | {% if field.auto_id %} 103 | 104 | {% endif %} 105 | 106 | {% for error in field.errors %} 107 | {{ error }} 108 | {% endfor %} 109 | 110 | {% if field.help_text %} 111 |

112 | {{ field.help_text|safe }} 113 |

114 | {% endif %} 115 | 116 | {% else %} 117 | {% if classes.icon %} 118 | {% include 'materializecssform/field_icon.html' %} 119 | {% endif %} 120 | 125 | {% if field.auto_id %} 126 | 127 | {% endif %} 128 | 129 | {% for error in field.errors %} 130 | {{ error }} 131 | {% endfor %} 132 | 133 | {% if field.help_text %} 134 |

135 | {{ field.help_text|safe }} 136 |

137 | {% endif %} 138 | 139 | {% endif %} 140 | 141 |
142 | 143 | {% elif field|is_multiple_checkbox %} 144 |
145 | {% if field.auto_id %} 146 | 147 | {% endif %} 148 |
149 |
    150 | 151 | {% for choice in field %} 152 | 153 |
  • 154 | 158 |
  • 159 | 160 | {% endfor %} 161 | 162 |
163 | {% for error in field.errors %} 164 | {{ error }} 165 | {% endfor %} 166 | 167 | {% if field.help_text %} 168 |

169 | {{ field.help_text|safe }} 170 |

171 | {% endif %} 172 |
173 | 174 |
175 | 176 | {% elif field|is_textarea %} 177 |
178 | {% if classes.icon %} 179 | {% include 'materializecssform/field_icon.html' %} 180 | {% endif %} 181 | 182 | {% if field.auto_id %} 183 | 184 | {% endif %} 185 | 186 | {% for error in field.errors %} 187 |

{{ error }}

188 | {% endfor %} 189 | 190 | {% if field.help_text %} 191 |

192 | {{ field.help_text|safe }} 193 |

194 | {% endif %} 195 |
196 | 197 | {% elif field|is_file %} 198 |
199 | 200 | {% for error in field.errors %} 201 |

{{ error }}

202 | {% endfor %} 203 | 204 |
205 |
206 | {{ field.label }} 207 | {% if classes.icon %} 208 | {% include 'materializecssform/field_icon.html' %} 209 | {% endif %} 210 | {{ field }} 211 |
212 |
213 | 214 |
215 |
216 | 217 |
218 | {% else %} 219 | 220 |
221 | {% if classes.icon %} 222 | {% include 'materializecssform/field_icon.html' %} 223 | {% endif %} 224 | {{ field }} 225 | {% if field.auto_id %} 226 | 227 | {% endif %} 228 | 229 | {% for error in field.errors %} 230 |

{{ error }}

231 | {% endfor %} 232 | 233 | {% if field.help_text %} 234 |

235 | {{ field.help_text|safe }} 236 |

237 | {% endif %} 238 |
239 | 240 | {% endif %} 241 | -------------------------------------------------------------------------------- /materializecssform/templates/materializecssform/field_icon.html: -------------------------------------------------------------------------------- 1 | {% if icon_set == 'fontawesome' %} 2 | 3 | {% elif icon_set == 'glyphicon' %} 4 | 5 | {% else %} 6 | {{ classes.icon }} 7 | {% endif %} -------------------------------------------------------------------------------- /materializecssform/templates/materializecssform/form.html: -------------------------------------------------------------------------------- 1 | {% if form.non_field_errors %} 2 |
3 | {% for non_field_error in form.non_field_errors %} 4 | {{ non_field_error }} 5 | {% endfor %} 6 |
7 | {% endif %} 8 | 9 | {% for field in form.hidden_fields %} 10 | {{ field }} 11 | {% endfor %} 12 | 13 | {% for field in form.visible_fields %} 14 | {% include 'materializecssform/field.html' %} 15 | {% endfor %} 16 | 17 | -------------------------------------------------------------------------------- /materializecssform/templates/materializecssform/formset.html: -------------------------------------------------------------------------------- 1 | {{ formset.management_form }} 2 | 3 | {% for form in formset %} 4 | 5 | {% include "materializecssform/form.html" with form=form %} 6 | 7 | {% endfor %} 8 | -------------------------------------------------------------------------------- /materializecssform/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kalwalkden/django-materializecss-form/2244174c5d56377704cab96ef4f7108484f86c3d/materializecssform/templatetags/__init__.py -------------------------------------------------------------------------------- /materializecssform/templatetags/materializecss.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.template.loader import get_template 3 | from django import template 4 | from django.forms.fields import DateTimeField, DateField 5 | from django.http import QueryDict 6 | 7 | from materializecssform import config 8 | 9 | register = template.Library() 10 | 11 | 12 | @register.filter 13 | def materializecss(element, options={}): 14 | # Set default values if none of them are set 15 | label_cols = 's12' 16 | icon = '' 17 | 18 | if options: 19 | # Split options string into a list of arguments 20 | arguments = [arg.strip() for arg in options.split(',')] 21 | 22 | # Check the first argument to see if it's of form argument=value 23 | if '=' not in arguments[0]: 24 | # If not, it's a custom size, so use that 25 | label_cols = arguments[0] 26 | # Remove this from the arguments list 27 | arguments.pop(0) 28 | 29 | # Join the remaining arguments into a querystring for easy parsing 30 | options = '&'.join(arguments) 31 | qs = QueryDict(options) 32 | # Check to see if a custom size was passed in this fashion and if so prefer it 33 | if qs.get('custom_size'): 34 | label_cols = qs.get('custom_size') 35 | # Get icon if it's been set 36 | icon = qs.get('icon', default='') 37 | 38 | markup_classes = {'label': label_cols, 'value': '', 'single_value': '', 'icon': icon} 39 | return render(element, markup_classes) 40 | 41 | 42 | def _add_input_classes_widget(widget, field_errors): 43 | if _is_multi_widget(widget): 44 | for subwidget in widget.widgets: 45 | _add_input_classes_widget(subwidget, field_errors) 46 | elif not _is_checkbox_widget(widget) and not _is_multiple_checkbox_widget(widget) \ 47 | and not _is_radio_widget(widget) and not _is_file_widget(widget): 48 | classes = widget.attrs.get('class', '') 49 | if config.MATERIALIZECSS_VALIDATION: 50 | classes += ' validate' 51 | if field_errors: 52 | classes += ' invalid' 53 | widget.attrs['class'] = classes 54 | 55 | 56 | def add_input_classes(field): 57 | _add_input_classes_widget(field.field.widget, field.errors) 58 | 59 | 60 | def render(element, markup_classes): 61 | element_type = element.__class__.__name__.lower() 62 | 63 | # Get the icon set setting 64 | icon_set = config.MATERIALIZECSS_ICON_SET 65 | 66 | if element_type == 'boundfield': 67 | add_input_classes(element) 68 | template = get_template("materializecssform/field.html") 69 | context = {'field': element, 'classes': markup_classes, 'icon_set': icon_set} 70 | else: 71 | has_management = getattr(element, 'management_form', None) 72 | if has_management: 73 | for form in element.forms: 74 | for field in form.visible_fields(): 75 | add_input_classes(field) 76 | 77 | template = get_template("materializecssform/formset.html") 78 | context = {'formset': element, 'classes': markup_classes, 'icon_set': icon_set} 79 | else: 80 | for field in element.visible_fields(): 81 | add_input_classes(field) 82 | 83 | template = get_template("materializecssform/form.html") 84 | context = {'form': element, 'classes': markup_classes, 'icon_set': icon_set} 85 | 86 | return template.render(context) 87 | 88 | 89 | def _is_checkbox_widget(widget): 90 | return isinstance(widget, forms.CheckboxInput) 91 | 92 | 93 | def _is_multiple_checkbox_widget(widget): 94 | return isinstance(widget, forms.CheckboxSelectMultiple) 95 | 96 | 97 | def _is_radio_widget(widget): 98 | return isinstance(widget, forms.RadioSelect) 99 | 100 | 101 | def _is_file_widget(widget): 102 | return isinstance(widget, forms.FileInput) 103 | 104 | 105 | def _is_multi_widget(widget): 106 | return isinstance(widget, forms.MultiWidget) 107 | 108 | 109 | @register.filter 110 | def is_checkbox(field): 111 | return isinstance(field.field.widget, forms.CheckboxInput) 112 | 113 | 114 | @register.filter 115 | def is_textarea(field): 116 | return isinstance(field.field.widget, forms.Textarea) 117 | 118 | 119 | @register.filter 120 | def is_multiple_checkbox(field): 121 | return isinstance(field.field.widget, forms.CheckboxSelectMultiple) 122 | 123 | 124 | @register.filter 125 | def is_radio(field): 126 | return isinstance(field.field.widget, forms.RadioSelect) 127 | 128 | 129 | @register.filter 130 | def is_date_input(field): 131 | return isinstance(field.field, DateField) 132 | 133 | 134 | @register.filter 135 | def is_datetime_input(field): 136 | return isinstance(field.field, DateTimeField) 137 | 138 | 139 | @register.filter 140 | def is_file(field): 141 | return isinstance(field.field.widget, forms.FileInput) 142 | 143 | 144 | @register.filter 145 | def is_select(field): 146 | return isinstance(field.field.widget, forms.Select) 147 | 148 | 149 | @register.filter 150 | def is_select_multiple(field): 151 | return isinstance(field.field.widget, forms.SelectMultiple) 152 | -------------------------------------------------------------------------------- /materializecssform/tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import django 4 | from django.conf import settings 5 | 6 | settings.configure( 7 | DEBUG=True, 8 | DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "name": ":memory:"}}, 9 | MIDDLEWARE_CLASSES=[], 10 | INSTALLED_APPS=[], 11 | ) 12 | django.setup() 13 | 14 | 15 | class TestTags(unittest.TestCase): 16 | def test_materializecss_tag(self): 17 | from materializecssform.templatetags import materializecss # noqa 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=40.6.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | # Not necessary for packaging but every self-respecting Python 6 | # package should a) use black and b) fix the WRONG default. 7 | [tool.black] 8 | line-length = 79 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | import re 4 | 5 | from setuptools import find_packages, setup 6 | 7 | ################################################################### 8 | 9 | NAME = "django-materializecss-form" 10 | PACKAGES = find_packages() 11 | META_PATH = os.path.join("materializecssform", "meta.py") 12 | KEYWORDS = ["materialize", "django", "css", "materializecss", "django forms"] 13 | CLASSIFIERS = [ 14 | "Development Status :: 5 - Production/Stable", 15 | "Framework :: Django", 16 | "Intended Audience :: Developers", 17 | "Natural Language :: English", 18 | "License :: OSI Approved :: MIT License", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3", 22 | "Programming Language :: Python :: 3.4", 23 | "Programming Language :: Python :: 3.5", 24 | "Programming Language :: Python :: 3.6", 25 | "Programming Language :: Python :: 3.7", 26 | "Programming Language :: Python :: 3.8", 27 | "Programming Language :: Python :: Implementation :: CPython", 28 | "Programming Language :: Python :: Implementation :: PyPy", 29 | "Topic :: Software Development :: Libraries :: Python Modules", 30 | ] 31 | INSTALL_REQUIRES = [] 32 | 33 | ################################################################### 34 | 35 | 36 | HERE = os.path.abspath(os.path.dirname(__file__)) 37 | 38 | 39 | def read(*parts): 40 | """ 41 | Build an absolute path from *parts* and and return the contents of the 42 | resulting file. Assume UTF-8 encoding. 43 | """ 44 | with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: 45 | return f.read() 46 | 47 | 48 | META_FILE = read(META_PATH) 49 | 50 | 51 | def find_meta(meta): 52 | """ 53 | Extract __*meta*__ from META_FILE. 54 | """ 55 | meta_match = re.search( 56 | r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), META_FILE, re.M 57 | ) 58 | if meta_match: 59 | return meta_match.group(1) 60 | raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) 61 | 62 | 63 | if __name__ == "__main__": 64 | setup( 65 | name=NAME, 66 | description=find_meta("description"), 67 | license=find_meta("license"), 68 | url=find_meta("uri"), 69 | version=find_meta("version"), 70 | author=find_meta("author"), 71 | author_email=find_meta("email"), 72 | maintainer=find_meta("author"), 73 | maintainer_email=find_meta("email"), 74 | keywords=KEYWORDS, 75 | long_description=read("README.md"), 76 | long_description_content_type="text/markdown", 77 | packages=PACKAGES, 78 | zip_safe=False, 79 | classifiers=CLASSIFIERS, 80 | install_requires=INSTALL_REQUIRES, 81 | options={"bdist_wheel": {"universal": "1"}}, 82 | include_package_data=True, 83 | ) 84 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py37 3 | 4 | [testenv] 5 | deps = 6 | django 7 | commands = 8 | python materializecssform/tests.py 9 | --------------------------------------------------------------------------------