dk-tasklib 3.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,172 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # This file does only contain a selection of the most common options. For a
4
+ # full list see the documentation:
5
+ # http://www.sphinx-doc.org/en/stable/config
6
+
7
+ # -- Path setup --------------------------------------------------------------
8
+
9
+ # If extensions (or modules to document with autodoc) are in another directory,
10
+ # add these directories to sys.path here. If the directory is relative to the
11
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
12
+ #
13
+ import os
14
+ import sys
15
+ sys.path.insert(0, os.path.abspath('..'))
16
+
17
+
18
+ # -- Project information -----------------------------------------------------
19
+
20
+ project = '##{PACKAGE}'
21
+ copyright = '##{YEAR}, ##{AUTHOR}'
22
+ author = '##{AUTHOR}'
23
+
24
+ # The short X.Y version
25
+ version = '##{VERSION}'
26
+ # The full version, including alpha/beta/rc tags
27
+ release = '##{VERSION}'
28
+
29
+
30
+ # -- General configuration ---------------------------------------------------
31
+
32
+ # If your documentation needs a minimal Sphinx version, state it here.
33
+ #
34
+ # needs_sphinx = '1.0'
35
+
36
+ # Add any Sphinx extension module names here, as strings. They can be
37
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
38
+ # ones.
39
+ extensions = [
40
+ 'sphinx.ext.autodoc',
41
+ 'sphinx.ext.intersphinx',
42
+ 'sphinx.ext.todo',
43
+ 'sphinx.ext.viewcode',
44
+ ]
45
+
46
+ # Add any paths that contain templates here, relative to this directory.
47
+ templates_path = ['_templates']
48
+
49
+ # The suffix(es) of source filenames.
50
+ # You can specify multiple suffix as a list of string:
51
+ #
52
+ # source_suffix = ['.rst', '.md']
53
+ source_suffix = '.rst'
54
+
55
+ # The master toctree document.
56
+ master_doc = 'index'
57
+
58
+ # The language for content autogenerated by Sphinx. Refer to documentation
59
+ # for a list of supported languages.
60
+ #
61
+ # This is also used if you do content translation via gettext catalogs.
62
+ # Usually you set "language" from the command line for these cases.
63
+ language = 'en'
64
+
65
+ # List of patterns, relative to source directory, that match files and
66
+ # directories to ignore when looking for source files.
67
+ # This pattern also affects html_static_path and html_extra_path .
68
+ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
69
+
70
+ # The name of the Pygments (syntax highlighting) style to use.
71
+ pygments_style = 'sphinx'
72
+
73
+
74
+ # -- Options for HTML output -------------------------------------------------
75
+
76
+ # The theme to use for HTML and HTML Help pages. See the documentation for
77
+ # a list of builtin themes.
78
+ #
79
+ html_theme = 'alabaster'
80
+
81
+ # Theme options are theme-specific and customize the look and feel of a theme
82
+ # further. For a list of options available for each theme, see the
83
+ # documentation.
84
+ #
85
+ # html_theme_options = {}
86
+
87
+ # Add any paths that contain custom static files (such as style sheets) here,
88
+ # relative to this directory. They are copied after the builtin static files,
89
+ # so a file named "default.css" will overwrite the builtin "default.css".
90
+ html_static_path = ['_static']
91
+
92
+ # Custom sidebar templates, must be a dictionary that maps document names
93
+ # to template names.
94
+ #
95
+ # The default sidebars (for documents that don't match any pattern) are
96
+ # defined by theme itself. Builtin themes are using these templates by
97
+ # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
98
+ # 'searchbox.html']``.
99
+ #
100
+ # html_sidebars = {}
101
+
102
+
103
+ # -- Options for HTMLHelp output ---------------------------------------------
104
+
105
+ # Output file base name for HTML help builder.
106
+ htmlhelp_basename = '##{PACKAGE}doc'
107
+
108
+
109
+ # -- Options for LaTeX output ------------------------------------------------
110
+
111
+ latex_elements = {
112
+ # The paper size ('letterpaper' or 'a4paper').
113
+ #
114
+ # 'papersize': 'letterpaper',
115
+
116
+ # The font size ('10pt', '11pt' or '12pt').
117
+ #
118
+ # 'pointsize': '10pt',
119
+
120
+ # Additional stuff for the LaTeX preamble.
121
+ #
122
+ # 'preamble': '',
123
+
124
+ # Latex figure (float) alignment
125
+ #
126
+ # 'figure_align': 'htbp',
127
+ }
128
+
129
+ # Grouping the document tree into LaTeX files. List of tuples
130
+ # (source start file, target name, title,
131
+ # author, documentclass [howto, manual, or own class]).
132
+ latex_documents = [
133
+ (master_doc, '##{PACKAGE}.tex', '##{PACKAGE} Documentation',
134
+ '##{AUTHOR}', 'manual'),
135
+ ]
136
+
137
+
138
+ # -- Options for manual page output ------------------------------------------
139
+
140
+ # One entry per manual page. List of tuples
141
+ # (source start file, name, description, authors, manual section).
142
+ man_pages = [
143
+ (master_doc, '##{PACKAGE}', '##{PACKAGE} Documentation',
144
+ [author], 1)
145
+ ]
146
+
147
+
148
+ # -- Options for Texinfo output ----------------------------------------------
149
+
150
+ # Grouping the document tree into Texinfo files. List of tuples
151
+ # (source start file, target name, title, author,
152
+ # dir menu entry, description, category)
153
+ texinfo_documents = [
154
+ (master_doc, '##{PACKAGE}', '##{PACKAGE} Documentation',
155
+ author, '##{PACKAGE}', 'One line description of project.',
156
+ 'Miscellaneous'),
157
+ ]
158
+
159
+
160
+ # -- Extension configuration -------------------------------------------------
161
+
162
+ # -- Options for intersphinx extension ---------------------------------------
163
+
164
+ # Example configuration for intersphinx: refer to the Python standard library.
165
+ intersphinx_mapping = {
166
+ 'python': ('https://docs.python.org/3', None),
167
+ }
168
+
169
+ # -- Options for todo extension ----------------------------------------------
170
+
171
+ # If true, `todo` and `todoList` produce output, else they produce nothing.
172
+ todo_include_todos = True
@@ -0,0 +1,102 @@
1
+ """Commands installed by setup.py
2
+ """
3
+ # pragma: nocover
4
+ import argparse
5
+ import datetime
6
+ import os
7
+ import sys
8
+
9
+ import textwrap
10
+
11
+ from dkfileutils.path import Path
12
+ from .._version import __version__
13
+ from .pytemplate import PyTemplate
14
+ from ..runners import run
15
+
16
+ DIRNAME = Path(os.path.dirname(__file__))
17
+
18
+
19
+ def install_cmd(args):
20
+ """Install a basic task.py to the current directory.
21
+ """
22
+ cwd = Path.curdir()
23
+ tasks_file = cwd / 'tasks.py'
24
+ if tasks_file.exists() and not args.force:
25
+ print("tasks.py exists (use --force to overwrite)")
26
+ sys.exit(1)
27
+ taskbase = DIRNAME / 'taskbase.py'
28
+ txt = taskbase.read('rb')
29
+ txt = txt.replace(b'\r\n', b'\n')
30
+ t = PyTemplate(txt)
31
+ tasks_file.write(t.substitute(
32
+ VERSION=__version__
33
+ ))
34
+ if args.django:
35
+ add_django_to_docs_conf()
36
+
37
+
38
+ def create_docs_cmd(args):
39
+ cwd = Path.curdir()
40
+ docsdir = cwd / 'docs'
41
+ if docsdir.exists() and not args.force:
42
+ print("docs directory exists (use --force to overwrite)")
43
+ sys.exit(1)
44
+ confbase = DIRNAME / 'confbase.py'
45
+ txt = confbase.read('rb')
46
+ txt = txt.replace(b'\r\n', b'\n')
47
+ t = PyTemplate(txt)
48
+
49
+ docsdir.makedirs()
50
+ (docsdir / 'conf.py').write(t.substitute(
51
+ VERSION=run('python setup.py --version'),
52
+ PACKAGE=run('python setup.py --name'),
53
+ YEAR=datetime.date.today().year,
54
+ AUTHOR=run('python setup.py --author').strip()
55
+ ))
56
+
57
+
58
+ def add_django_to_docs_conf():
59
+ cwd = Path.curdir()
60
+ conf_file = cwd / 'docs' / 'conf.py'
61
+ if 'django.setup()' in conf_file.read():
62
+ print("./docs/conf.py already contains django.setup()")
63
+ return
64
+
65
+ src = conf_file.read('r')
66
+ pre, post = src.split('\n\n', 1)
67
+ conf_file.write(
68
+ pre + "\n\n" +
69
+ textwrap.dedent("""\
70
+ import django
71
+ django.setup()
72
+ """) + "\n\n" +
73
+ post
74
+ )
75
+
76
+
77
+ def main(args=None):
78
+ args = args or sys.argv[1:]
79
+ p = argparse.ArgumentParser()
80
+ commands = list(sorted([name[:-4] for name in globals()
81
+ if name.endswith('_cmd')]))
82
+
83
+ p.add_argument('command', help="run command (available commands: %s)" % ', '.join(commands))
84
+ p.add_argument('--version', action='version', version='%(prog)s ' + __version__)
85
+ p.add_argument('--verbose', '-v', action='store_true', help="verbose output")
86
+ p.add_argument('--force', '-f', action='store_true', help="force execution of commands.")
87
+ p.add_argument('--django', '-d', action='store_true', help="make django specific changes.")
88
+
89
+ args = p.parse_args(args)
90
+
91
+ if args.verbose:
92
+ print("ARGS:", args)
93
+
94
+ if args.command not in commands:
95
+ print("Unknown command:", args.command)
96
+ sys.exit(1)
97
+
98
+ globals()[args.command + '_cmd'](args)
99
+
100
+
101
+ if __name__ == "__main__":
102
+ main()
@@ -0,0 +1,16 @@
1
+ from string import Template
2
+
3
+
4
+ class PyTemplate(Template):
5
+ """
6
+ Template strings that can replace ##{PATTERN} instances.
7
+ """
8
+ def __init__(self, t):
9
+ if isinstance(t, bytes):
10
+ t = t.decode('u8')
11
+ super().__init__(t.replace('$', '$$').replace('##{', '${'))
12
+
13
+ def substitute(self, *args, **kw):
14
+ return super().substitute(
15
+ **{k.upper(): v for k, v in kw.items()}
16
+ )
@@ -0,0 +1,135 @@
1
+ """
2
+ Base version of package/tasks.py, created by version ##{VERSION} of
3
+
4
+ package/root/dir> dk-tasklib install
5
+
6
+ (it should reside in the root directory of your package)
7
+
8
+ This file defines tasks for the Invoke tool: http://www.pyinvoke.org
9
+
10
+ Basic usage::
11
+
12
+ inv -l # list all available tasks
13
+ inv build -f # build everything, forcefully
14
+ inv build --docs # only build the docs
15
+
16
+ dk-tasklib is a library of basic tasks that tries to automate common tasks.
17
+ dk-tasklib will attempt to install any tools/libraries/etc. that are required,
18
+ e.g. when running the task to compile x.less to x.css, it will check that
19
+ the lessc compiler is installed (and if not it will attempt to install it).
20
+
21
+ This file is an initial skeleton, you are supposed to edit and add to it so it
22
+ will fit your use case.
23
+
24
+
25
+ """
26
+ # pragma: nocover
27
+ import os
28
+ import warnings
29
+
30
+ from dkfileutils.changed import changed
31
+ from dkfileutils.path import Path
32
+ from dktasklib.wintask import task
33
+ from invoke import Collection
34
+
35
+ from dktasklib import docs as doctools
36
+ from dktasklib import lessc
37
+ from dktasklib import version, upversion
38
+ from dktasklib.manage import collectstatic
39
+ from dktasklib.package import Package, package
40
+ from dktasklib.watch import Watcher
41
+ # from dktasklib.publish import publish
42
+
43
+ #: where tasks.py is located (root of package)
44
+ DIRNAME = Path(os.path.dirname(__file__))
45
+
46
+ # collectstatic
47
+ # --------------
48
+ # Specify which settings file should be used when running
49
+ # `python manage.py collectstatic` (must be on the path or package root
50
+ # directory).
51
+ DJANGO_SETTINGS_MODULE = ''
52
+
53
+ # .less
54
+ # ------
55
+ # there should be a mypkg/mypkg/less/mypkg.less file that imports any other
56
+ # needed sources
57
+
58
+ # ============================================================================
59
+ # autodoc is in a separate process, so can't use settings.configure().
60
+ HAVE_SETTINGS = bool(DJANGO_SETTINGS_MODULE)
61
+ if not HAVE_SETTINGS and (DIRNAME / 'settings.py').exists():
62
+ # look for a dummy settings.py module in the root of the package.
63
+ DJANGO_SETTINGS_MODULE = 'settings'
64
+ if DJANGO_SETTINGS_MODULE:
65
+ os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
66
+ WARN_ABOUT_SETTINGS = not bool(DJANGO_SETTINGS_MODULE)
67
+
68
+
69
+ @task
70
+ def build(ctx, less=False, docs=False, force=False):
71
+ """Build everything and collectstatic.
72
+ """
73
+ specified = any([less, docs])
74
+ buildall = not specified
75
+
76
+ if buildall or less:
77
+ less_fname = ctx.pkg.source_less / ctx.pkg.name + '.less'
78
+ if less_fname.exists():
79
+ lessc.LessRule(
80
+ ctx,
81
+ src='{pkg.source_less}/{pkg.name}.less',
82
+ dst='{pkg.django_static}/{pkg.name}/css/{pkg.name}-{version}.min.css',
83
+ force=force
84
+ )
85
+ elif less:
86
+ warnings.warn(
87
+ "WARNING: build --less specified, but no file at: " + less_fname
88
+ )
89
+
90
+ if buildall or docs:
91
+ if WARN_ABOUT_SETTINGS:
92
+ warnings.warn(
93
+ "autodoc might need a dummy settings file in the root of "
94
+ "your package. Since it runs in a separate process you cannot"
95
+ "use settings.configure()"
96
+ )
97
+ doctools.build(ctx, force=force)
98
+
99
+ if HAVE_SETTINGS and (force or changed(ctx.pkg.django_static)):
100
+ collectstatic(ctx, DJANGO_SETTINGS_MODULE, force=force)
101
+
102
+
103
+ @task
104
+ def watch(ctx):
105
+ """Automatically run build whenever a relevant file changes.
106
+ """
107
+ watcher = Watcher(ctx)
108
+ watcher.watch_directory(
109
+ path='{pkg.source_less}', ext='.less',
110
+ action=lambda e: build(ctx, less=True)
111
+ )
112
+ watcher.watch_directory(
113
+ path='{pkg.docs}', ext='.rst',
114
+ action=lambda e: build(ctx, docs=True)
115
+ )
116
+ watcher.start()
117
+
118
+
119
+ # individual tasks that can be run from this project
120
+ ns = Collection(
121
+ build,
122
+ watch,
123
+ lessc,
124
+ doctools,
125
+ version, upversion,
126
+ package,
127
+ collectstatic,
128
+ # publish,
129
+ )
130
+ ns.configure({
131
+ 'pkg': Package(),
132
+ 'run': {
133
+ 'echo': True
134
+ }
135
+ })
@@ -0,0 +1,11 @@
1
+ """
2
+ Global state.
3
+ """
4
+
5
+
6
+ class Environment:
7
+ def __call__(self, ctx):
8
+ return ctx
9
+
10
+
11
+ env = Environment()
@@ -0,0 +1,200 @@
1
+ import sys
2
+ import warnings
3
+
4
+ import invoke
5
+ from dkfileutils.which import get_executable
6
+ from dktasklib import Package
7
+ from dktasklib.utils import win32
8
+ from dktasklib import runners
9
+
10
+
11
+ class MissingCommand(Exception):
12
+ """Exception thrown when a command (executable) is not found.
13
+ """
14
+ pass
15
+
16
+
17
+ # noinspection PyShadowingNames
18
+ class Executables:
19
+ """Class for finding executables on the host system.
20
+ """
21
+ def __init__(self):
22
+ self._cache = {}
23
+ self._ctx = None
24
+
25
+ @property
26
+ def ctx(self):
27
+ if self._ctx is None:
28
+ self._ctx = invoke.Context()
29
+ return self._ctx
30
+
31
+ def require(self, *dependencies):
32
+ """Ensure that all dependencies are available.
33
+ You should not need to call this yourself, use the :func:`requires`
34
+ decorator instead.
35
+ """
36
+ for dep in dependencies:
37
+ self.find(dep)
38
+
39
+ def find(self, name, requires=(), install_txt=''):
40
+ """Find the executable named ``name`` on the :envvar:`PATH`.
41
+
42
+ Args:
43
+ name (str):
44
+ name of executable to find.
45
+ requires (List[str]):
46
+ list of executables to find first.
47
+ install_txt (str):
48
+ instructions for how to install the
49
+ executable if it is not found.
50
+ """
51
+ if name not in self._cache:
52
+ self.require(*requires)
53
+
54
+ if hasattr(self, 'find_' + name):
55
+ self._cache[name] = getattr(self, 'find_' + name)()
56
+ else:
57
+ self._cache[name] = self._find_exe(name, requires, install_txt)
58
+ return self._cache[name]
59
+
60
+ def _find_exe(self, name, requires=(), install_txt=None):
61
+ fexe = get_executable(name)
62
+ if not fexe: # pragma: nocover
63
+ # try $PKG/node_modules/.bin/<exe|cmd>
64
+ noderoot = Package().root / 'node_modules/.bin'
65
+ if name + '.cmd' in noderoot:
66
+ return str(noderoot / (name + '.cmd'))
67
+
68
+ if not install_txt: # pragma: nocover
69
+ install_txt = "Missing command: %r" % name
70
+ if requires:
71
+ install_txt += " [requires: %s]" % requires
72
+ raise MissingCommand(install_txt)
73
+ return fexe
74
+
75
+ def find_wheel(self):
76
+ exename = 'wheel'
77
+ exepath = get_executable(exename)
78
+ if not exepath:
79
+ pip = get_executable('pip')
80
+ cmd = pip + ' install wheel[signatures]'
81
+ if win32:
82
+ runners.run(cmd)
83
+ exepath = get_executable(exename)
84
+ # generate signing key if downloading wheel
85
+ runners.run(exepath + ' keygen')
86
+ else:
87
+ raise MissingCommand("Missing wheel (%s)" % cmd)
88
+ print('Your ~/.pypirc file should have a [pypi] section instead of a [server-login] section')
89
+ return exepath
90
+
91
+ def find_twine(self):
92
+ exename = 'twine'
93
+ exepath = get_executable(exename)
94
+ if not exepath:
95
+ pip = get_executable('pip')
96
+ cmd = pip + ' install twine'
97
+ if win32:
98
+ runners.run(cmd)
99
+ exepath = get_executable(exename)
100
+ else:
101
+ raise MissingCommand("Missing twine (%s)" % cmd)
102
+ print('Your ~/.pypirc file should have a [pypi] section instead of a [server-login] section')
103
+ return exepath
104
+
105
+ def find_uglify(self):
106
+ exename = 'uglifyjs'
107
+ exepath = get_executable(exename)
108
+ if not exepath:
109
+ npminstall = "npm install -g uglify-js --no-color"
110
+ if win32:
111
+ self.ctx.run(npminstall, echo=False, encoding="utf-8")
112
+ exepath = get_executable(exename)
113
+ else:
114
+ raise MissingCommand("Missing uglifyjs (%s)" % npminstall)
115
+ return exepath
116
+
117
+ def find_browserify(self):
118
+ exename = 'browserify'
119
+ exepath = get_executable(exename)
120
+ npminstall = "npm install -g browserify --no-color"
121
+ if not exepath:
122
+ if win32:
123
+ self.ctx.run(npminstall, echo=True, encoding="utf-8")
124
+ exepath = get_executable(exename)
125
+ else:
126
+ raise MissingCommand("Missing browserify (%s)" % npminstall)
127
+ return exepath
128
+
129
+ def find_babili(self):
130
+ exename = 'babili'
131
+ exepath = get_executable(exename)
132
+ npminstall = "npm install -g babili --no-color"
133
+ if not exepath:
134
+ if win32:
135
+ self.ctx.run(npminstall, echo=False, encoding="utf-8")
136
+ exepath = get_executable(exename)
137
+ else:
138
+ raise MissingCommand("Missing babili (%s)" % npminstall)
139
+ return exepath
140
+
141
+ def find_babel(self):
142
+ exename = 'babel'
143
+ exepath = get_executable(exename)
144
+ npminstall = "npm install -g babel-cli --no-color"
145
+ if not exepath:
146
+ if win32:
147
+ self.ctx.run(npminstall, echo=False, encoding="utf-8")
148
+ exepath = get_executable(exename)
149
+ else:
150
+ raise MissingCommand("Missing babel (%s)" % npminstall)
151
+ return exepath
152
+
153
+ def find_nodejs(self): # pragma: nocover
154
+ """Find :program:`node`.
155
+ """
156
+ if sys.platform == 'win32':
157
+ node_exe = get_executable('node')
158
+ else:
159
+ node_exe = get_executable('nodejs') or get_executable('node')
160
+
161
+ if not node_exe: # pragma: nocover
162
+ raise MissingCommand("""
163
+ Install Node.js using your OS package manager
164
+ https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
165
+ """)
166
+ return node_exe
167
+
168
+ def find_npm(self):
169
+ """Find the node package manager (:program:`npm`).
170
+ """
171
+ npm_exe = get_executable('npm')
172
+ if not npm_exe: # pragma: nocover
173
+ raise MissingCommand("""
174
+ Install Node.js using your OS package manager
175
+ https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
176
+ """)
177
+ return npm_exe
178
+
179
+
180
+ #: public interface to the :py:class:`Executables` class
181
+ exe = Executables()
182
+
183
+
184
+ def requires(*deps):
185
+ """Decorator to declare global dependencies/requirements.
186
+
187
+ Usage (``@task`` must be last)::
188
+
189
+ @requires('nodejs', 'npm', 'lessc')
190
+ @task
191
+ def mytask(..)
192
+
193
+ """
194
+ def _wrapper(fn):
195
+ try:
196
+ exe.require(*deps)
197
+ except MissingCommand as e:
198
+ warnings.warn(str(e))
199
+ return fn
200
+ return _wrapper
dktasklib/help.py ADDED
@@ -0,0 +1,17 @@
1
+ from dktasklib.wintask import task
2
+
3
+
4
+ @task(default=True)
5
+ def help(ctx):
6
+ """
7
+ """
8
+ ctx.run('invoke --help')
9
+
10
+
11
+ @task(default=True)
12
+ def list(ctx):
13
+ """Show help, basically an alias for --help.
14
+ This task can be removed once the fix to this issue is released:
15
+ https://github.com/pyinvoke/invoke/issues/180
16
+ """
17
+ ctx.run('invoke --list')