Skip to content

Commit 1ca926c

Browse files
authored
Version 0.7.0 (#23)
* Removing argparse / command line option. Adding first tests and docs to new functions. * Adding defaults confignamespace methods, adding change_logger_level, fixes * [skip ci] Adding cross version run command * Adding tests, docstrings and updates for run. * Fixing nix tests * Fixing timeout version discrepancies. * PY2 vs PY3 testing * Python 2.6 is dumb * [ci skip] Fix import error in wrappers * Fix setup.py error * [skip ci] Adding new tasker ability * [skip ci] Adding new download function * Making logger safer, expanding run_in_pool * Pythox 2.x fixes * [skip ci] Adding pushd and popd as well as timed example of find fines compared to find * [skip ci] Command line helpers * [skip ci] Adding match specifications and readme updates * [skip ci] Expanding readme * [skip ci] Better command for running stuff from interpreter, expansion of readme * Overhauled tasker, should be working * Rename tasker to something meaningful. Adding ability to stop when tasklist finished * Adding basic file server * Making clear that it is a file server * Testing a bit more of download * Adding reusable tests * Fixing called process errors for non 3.5 pythons * maybe 2.6 will work this time * Windows and pypy fixes. * python 2.6 subprocess fix * Adding new documentation. Improving testing. * Adding bad size documentation * Threaded instead of MP FileServer * Increase test coverage * Preparations for Version 0.6.0 * Updating documentation for Version 0.6.0 * Trying out new documentation * [ci skip] hopefully last doc fixes * Adding find and now functions, protecting extension keys, adding glob ability with find, adding time_it wrapper. * Moving CLI helpers to their own section not imported by default. * [ci skip] Documentation! * [ci skip] Adding cat, and placeholder for tail * Fixing tests to be based properly. Adding queue_it function. * Adding depth to find files * Adding tail command * Adding splice and documentation * More documentation, moving imports to right place. * documentation and bug fixes * Adding logging helpers (untested), fixing imports, moving shared variables to their own file. * Tests and documentation * Python 2.6 is stupid * Figuring out python 2.6 is stupid properly * Figured out logging issue. * Adding tests for reuse * Adding docs and tests for new logging functions. * Adding tests for command queue tasker * Adding archive_all function * Adding test details * Clara's testing abilities * Adding copy command for CLI * Adding tests, and stream logger for CLI stuff * Docs, match_case applies to ext
1 parent 872d8df commit 1ca926c

22 files changed

+1513
-485
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ python:
77
- "3.3"
88
- "3.4"
99
- "3.5"
10+
- "3.6-dev"
1011
- "pypy"
1112
before_install:
1213
- sudo apt-get -qq update

CHANGES.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
Changelog
22
=========
33

4+
Version 0.7.0
5+
-------------
6+
7+
- Adding archive_all and now methods
8+
- Adding logger helpers to add stream and file handlers
9+
- Adding depth and abspath to find files methods
10+
- Adding head, tail, cat bash equivalents
11+
- Adding command queue to Tasking class, to give commands asynchronously and without directly referencing the instance
12+
- Changing test suite to have a common file it pulls imports and info from
13+
- Changing logger helpers to accept string instead of logger
14+
- Breaking change: Moving log formats from variables to Namespace log_formats
15+
- Breaking change: Moving command line helpers to cli
16+
- Breaking change: Command line helpers are not imported by default, should now use: from reusables.cli import *
17+
- Breaking change: join_root has been better named join_here
18+
419
Version 0.6.1
520
-------------
621

README.rst

Lines changed: 167 additions & 97 deletions
Large diffs are not rendered by default.

doc/source/cli.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Command Line Helpers
2+
====================
3+
4+
.. automodule:: reusables.cli
5+
:members:
6+
:undoc-members:

reusables/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .wrappers import *
88
from .multiprocess_helpers import *
99
from .web import *
10+
from .shared_variables import *
1011

1112
__author__ = "Chris Griffith"
12-
__version__ = "0.6.1"
13+
__version__ = "0.7.0"

reusables/cli.py

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#!/usr/bin/env python
2+
# -*- coding: UTF-8 -*-
3+
#
4+
# Part of the Reusables package.
5+
#
6+
# Copyright (c) 2014-2016 - Chris Griffith - MIT License
7+
"""
8+
Functions to only be used on Interactive instances to ease life.
9+
10+
Designed to be used as a start import. `from reusables.cli import *`
11+
12+
"""
13+
import os as _os
14+
import logging as _logging
15+
import shutil as _shutil
16+
17+
# Keep touch and download import so it can be imported with other CLI commands
18+
from .shared_variables import *
19+
from .reusables import run, win_based, find_all_files, touch
20+
from .web import download
21+
from .log import add_stream_handler
22+
23+
_logger = _logging.getLogger("reusables.cli")
24+
add_stream_handler("reusables.cli")
25+
26+
_saved_paths = []
27+
28+
29+
def cmd(command, ignore_stderr=False, raise_on_return=False, timeout=None,
30+
encoding="utf-8"):
31+
""" Run a shell command and have it automatically decoded and printed
32+
33+
:param command: Command to run as str
34+
:param ignore_stderr: To not print stderr
35+
:param raise_on_return: Run CompletedProcess.check_returncode()
36+
:param timeout: timeout to pass to communicate if python 3
37+
:param encoding: How the output should be decoded
38+
"""
39+
result = run(command, timeout=timeout, shell=True)
40+
if raise_on_return:
41+
result.check_returncode()
42+
print(result.stdout.decode(encoding))
43+
if not ignore_stderr and result.stderr:
44+
print(result.stderr.decode(encoding))
45+
46+
47+
def pushd(directory):
48+
"""Change working directories in style and stay organized!
49+
50+
:param directory: Where do you want to go and remember?
51+
:return: saved directory stack
52+
"""
53+
directory = _os.path.expanduser(directory)
54+
_saved_paths.insert(0, _os.path.abspath(_os.getcwd()))
55+
_os.chdir(directory)
56+
return [directory] + _saved_paths
57+
58+
59+
def popd():
60+
"""Go back to where you once were.
61+
62+
:return: saved directory stack
63+
"""
64+
try:
65+
directory = _saved_paths.pop(0)
66+
except IndexError:
67+
return [_os.getcwd()]
68+
_os.chdir(directory)
69+
return [directory] + _saved_paths
70+
71+
72+
def pwd():
73+
"""Get the current working directory"""
74+
return _os.getcwd()
75+
76+
77+
def cd(directory):
78+
"""Change working directory, with built in user (~) expansion
79+
80+
:param directory: New place you wanted to go
81+
"""
82+
_os.chdir(_os.path.expanduser(directory))
83+
84+
85+
def ls(params="", directory=".", printed=True):
86+
"""Know the best python implantation of ls? It's just to subprocess ls...
87+
(uses dir on windows).
88+
89+
:param params: options to pass to ls or dir
90+
:param directory: if not this directory
91+
:param printed: If you're using this, you probably wanted it just printed
92+
:return: if not printed, you can parse it yourself
93+
"""
94+
command = "{0} {1} {2}".format("ls" if not win_based else "dir",
95+
params, directory)
96+
response = run(command, shell=True) # Shell required for windows
97+
response.check_returncode()
98+
if printed:
99+
print(response.stdout.decode("utf-8"))
100+
else:
101+
return response.stdout
102+
103+
104+
def find(name=None, ext=None, directory=".", match_case=False,
105+
disable_glob=False, depth=None):
106+
""" Designed for the interactive interpreter by making default order
107+
of find_all_files faster.
108+
109+
:param name: Part of the file name
110+
:param ext: Extensions of the file you are looking for
111+
:param directory: Top location to recursively search for matching files
112+
:param match_case: If name has to be a direct match or not
113+
:param disable_glob: Do not look for globable names or use glob magic check
114+
:param depth: How many directories down to search
115+
:return: list of all files in the specified directory
116+
"""
117+
return find_all_files(directory=directory, ext=ext, name=name,
118+
match_case=match_case, disable_glob=disable_glob,
119+
depth=depth)
120+
121+
122+
def head(file_path, lines=10, encoding="utf-8", printed=True,
123+
errors='strict'):
124+
"""
125+
Read the first N lines of a file, defaults to 10
126+
127+
:param file_path: Path to file to read
128+
:param lines: Number of lines to read in
129+
:param encoding: defaults to utf-8 to decode as, will fail on binary
130+
:param printed: Automatically print the lines instead of returning it
131+
:param errors: Decoding errors: 'strict', 'ignore' or 'replace'
132+
:return: if printed is false, the lines are returned as a list
133+
"""
134+
data = []
135+
with open(file_path, "rb") as f:
136+
for _ in range(lines):
137+
try:
138+
if python_version >= (2, 7):
139+
data.append(next(f).decode(encoding, errors=errors))
140+
else:
141+
data.append(next(f).decode(encoding))
142+
except StopIteration:
143+
break
144+
if printed:
145+
print("".join(data))
146+
else:
147+
return data
148+
149+
150+
def cat(file_path, encoding="utf-8", errors='strict'):
151+
"""
152+
^-^
153+
(-.-)
154+
|.|
155+
/ \\
156+
| | _/
157+
| || | |
158+
\_||_/_/
159+
160+
:param file_path: Path to file to read
161+
:param encoding: defaults to utf-8 to decode as, will fail on binary
162+
:param errors: Decoding errors: 'strict', 'ignore' or 'replace'
163+
"""
164+
165+
with open(file_path, "rb") as f:
166+
if python_version >= (2, 7):
167+
print(f.read().decode(encoding, errors=errors))
168+
else:
169+
print(f.read().decode(encoding))
170+
171+
172+
def tail(file_path, lines=10, encoding="utf-8",
173+
printed=True, errors='strict'):
174+
"""
175+
A really silly way to get the last N lines, defaults to 10.
176+
177+
178+
:param file_path: Path to file to read
179+
:param lines: Number of lines to read in
180+
:param encoding: defaults to utf-8 to decode as, will fail on binary
181+
:param printed: Automatically print the lines instead of returning it
182+
:param errors: Decoding errors: 'strict', 'ignore' or 'replace'
183+
:return: if printed is false, the lines are returned as a list
184+
"""
185+
data = []
186+
187+
with open(file_path, "rb") as f:
188+
for line in f:
189+
if python_version >= (2, 7):
190+
data.append(line.decode(encoding, errors=errors))
191+
else:
192+
data.append(line.decode(encoding))
193+
if len(data) > lines:
194+
data.pop(0)
195+
if printed:
196+
print("".join(data))
197+
else:
198+
return data
199+
200+
201+
def cp(src, dst, overwrite=False):
202+
"""
203+
Copy files to a new location.
204+
205+
:param src: list (or string) of paths of files to copy
206+
:param dst: file or folder to copy item(s) to
207+
:param overwrite: IF the file already exists, should I overwrite it?
208+
"""
209+
210+
if not isinstance(src, list):
211+
src = [src]
212+
213+
dst = _os.path.expanduser(dst)
214+
dst_folder = _os.path.isdir(dst)
215+
216+
if len(src) > 1 and not dst_folder:
217+
raise OSError("Cannot copy multiple item to same file")
218+
219+
for item in src:
220+
source = _os.path.expanduser(item)
221+
destination = (dst if not dst_folder else
222+
_os.path.join(dst, _os.path.basename(source)))
223+
if not overwrite and _os.path.exists(destination):
224+
_logger.warning("Not replacing {0} with {1}, overwrite not enabled"
225+
"".format(destination, source))
226+
continue
227+
228+
_shutil.copy(source, destination)

0 commit comments

Comments
 (0)