diff --git a/README.md b/README.md
index 7b8d2a5..57902fb 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
-### pip-date -- Date your pip packages!
+### pip-date - Date your pip packages!
-[![PyPI version][1]][2]
-[![pypi supported versions][3]][4]
+[![pypi supported versions][1]][2]
+[![PyPI version][3]][4]
[![Maintenance][5]][6]
[![GitHub last commit][7]][8]
[![Average time to resolve an issue][9]][10]
-[1]: https://badge.fury.io/py/pip-date.svg
-[2]: https://badge.fury.io/py/pip-date
-[3]: https://img.shields.io/pypi/pyversions/pip-date.svg
-[4]: https://pypi.python.org/pypi/pip-date
+[1]: https://img.shields.io/pypi/pyversions/pip-date.svg
+[2]: https://pypi.python.org/pypi/pip-date
+[3]: https://badge.fury.io/py/pip-date.svg
+[4]: https://badge.fury.io/py/pip-date
[5]: https://img.shields.io/badge/Maintained%3F-yes-green.svg
[6]: https://GitHub.com/E3V3A/pip-date/graphs/commit-activity
[7]: https://img.shields.io/github/last-commit/E3V3A/pip-date.svg
@@ -21,7 +21,7 @@ A simple *Python3* CLI tool to show the installation or modification times of al
| STATUS: | Version | Date | Maintained? |
|:------- |:------- |:---- |:----------- |
-| Working | `1.0.1` | 2018-11-26 | YES |
+| Working | `1.0.2` | 2018-12-02 | YES |
---
@@ -81,8 +81,17 @@ and you don't really know what it is going to do.
**Q:** *What else is included?*
-There is also a small script called `pipbyday` that will print a simple table with:
-`mTime/aTime` + `package-name` + `package-version`, sorted by time.
+* A script called **`pip-describe`**, that will do what *pip* doesn't, which is to show
+the full text package description from PyPI, for a given *package*. Usually the README.
+
+* A script called **`pipbyday`**, that will print a simple table with:
+ `mTime/aTime` + `package-name` + `package-version`, sorted by time.
+
+* A script called **`pyfileinfo`**, that will show detailed file and date information
+for a given file using python's `os.stat` info.
+
+* A script called **`pyOSinfo`**, that will print a number of *os, system*
+and *platform* variables, as seen by your Python interpreter.
**Q:** *Will I continue to support this tool?*
@@ -94,7 +103,12 @@ something just send me a PR, or at the very least, a detailed code snippet of wh
### Dependencies
-None. (Just what you already have: [Python3](https://www.python.org/) and [pip](https://github.com/pypa/pip/).)
+
+* [requests](https://github.com/requests/requests) - used by `pip-describe` to get PyPI info
+
+and what you already have:
+* [Python3](https://www.python.org/)
+* [pip](https://github.com/pypa/pip/).
### Installation
@@ -108,7 +122,7 @@ pip install pip-date
```
-**For manual installation:**
+**For single file installation:**
```bash
cd /usr/bin/
@@ -135,57 +149,6 @@ pip-date # When it's in your PATH
---
-### DYI PyPI Packaging
-
-For your convenience, I will show you how to make a **simple** *python-only-script* pip-installable package like this one.
-Just follow these steps. (Don't bother reading elsewhere, because 99.9% of Google's results are already outdated!)
-To get started, you have to make sure you have already installed: `setuptools`, `wheel` and `twine`.
-
-Then you need to register and get credentials for 2 accounts:
-
-- https://pypi.org/account/register/ -- The **Live** PyPI
-- https://test.pypi.org/account/register/ -- The Test PyPI
-
-
-Then Setup and edit:
-
-- **`~/.pipyrc`** - for adding the Username/Password credentials to `testpypi` and `pypi` repositories
-- **`__init__.py`** - for name and version (*but can be empty*)
-- **`setup.cfg`** - for distribution Python2/3 compatibility
-- **`setup.py`** - for all package details
-
-
-You need to edit the following files:
-
-```bash
-__init__.py # Can be empty
-CHANGES.txt # Can be left out
-LICENSE.txt
-MyPyScript # Your Python Script
-README.md
-setup.cfg # Python2 or 3 or both?
-setup.py # ALL your package details
-```
-
-
-Finally, to create the package, test it and upload it:
-
-```bash
-cd pip-date
-python3 setup.py bdist_wheel # create a wheel distribution: pip_date-1.0.0-py3-none-any.whl
-twine check dist/* # Check if your dist long-description will render correctly on PyPI
-twine upload -r pypitest dist/* # Upload the project to PyPI with the "pypitest" index-server from ~/.pypirc
-# check your upload at:
-# https://test.pypi.org/project/pip-date/
-
-# Make a test-install with:
-pip install -i https://test.pypi.org/simple/ pip-date
-# If all ok, then delete from test.pypi.org and re-upload to live PyPI
-twine upload -r pypi dist/*
-```
-
----
-
### References:
**Time Stamps**
@@ -202,7 +165,8 @@ that it has a Windows FS that need *ctime*, and that anything else should use *m
Then we use: `os.path.getctime(pkg_loc)` to get the file time stamp.
-For all the gory details, see: [here](https://linuxhandbook.com/file-timestamps/),
+For all the gory details, see:
+[here](https://linuxhandbook.com/file-timestamps/),
[here](https://www.unixtutorial.org/atime-ctime-mtime-in-unix-filesystems/) and
[here](https://en.wikipedia.org/wiki/MAC_times).
@@ -237,6 +201,13 @@ For all the gory details, see: [here](https://linuxhandbook.com/file-timestamps/
projects, like *numpy*.
+---
+
+#### Recommeded Similar Tools:
+
+- **[pip-check](https://github.com/bartTC/pip-check/)** - Check you pip package update status with nice ANSI colored CLI
+- **[pip-chill](https://github.com/rbanffy/pip-chill)** - Lists only the dependencies (or not) of installed packages
+
---
#### Bugs and Warnings
@@ -246,12 +217,6 @@ None
#### ToDo / Help Needed
-- [ ] improve the time stamp (TS) heuristic to use more reliable files to search for
-- [ ] improve the package type heuristic to show how a package was installed (*wheel* or *sdist*)
-- [ ] add an `Environment` column, to show in what virtual environment a package was installed in.
-- [ ] improve highlighting of special package dependencies, such as [these](https://packaging.python.org/key_projects/).
- (e.g. Current implementation would for 'pip' also highlight any package with "pip" in it.)
-
See issues marked [ToDo](https://github.com/E3V3A/pip-date/issues?q=is%3Aopen+is%3Aissue+label%3AToDo).
#### Contribution
@@ -268,9 +233,10 @@ Feel free to fork, break, fix and contribute. Enjoy!
#### License
-[![GitHub license][21]][22]
+[![GitHub license][21]][22]
A license to :sparkling_heart:!
+I use `GPLv3` because sharing code modifications is more beneficial for the world.
[11]: https://ci.appveyor.com/api/projects/status/github/pip-date/pip-date?branch=master&svg=true
[12]: https://ci.appveyor.com/project/pip-date/pip-date
diff --git a/pip-date b/pip-date
index 16ffb03..8ab2564 100755
--- a/pip-date
+++ b/pip-date
@@ -1,13 +1,16 @@
#!/usr/bin/env python3
-# pipdate - Show the install date of all pip-installed python3 packages
+# pip-date - Show the install date of all pip-installed python3 packages
# -*- coding: utf-8 -*-
#----------------------------------------------------------------------
+# Author: E:V:A
+# Date: 2018-12-01
+# Version: 1.0.2
+# License: GPLv3
+# URL: https://github.com/E3V3A/pip-date/
+#----------------------------------------------------------------------
# ToDo:
# [ ] better cehck for cTime when using multiple versions:
# usually the first version should be install date...
-# [x] Add egg paths: -py3.6.egg-info
-# [x] if you are generating a filename from this value you should combine it
-# with a call to to_filename() so all dashes ("-"") are replaced by underscores ("_"). See to_filename().
# [/] fix rounding of floats in [a/c/m]Time
# [ ] If using Windows FS, then use cTime, if using *nix FS, use mTime ["platform.architecture()"]
#
@@ -19,9 +22,9 @@
# - [ ] '-v' : THIS program version
# - [ ] '-t ' : To highlight packages installed ago
#
-# References:
-# [1]
-# [2]
+# References:
+# [1] https://linuxhandbook.com/file-timestamps/
+# [2] https://www.unixtutorial.org/atime-ctime-mtime-in-unix-filesystems/
#----------------------------------------------------------------------
import re, os, sys, subprocess
import site, pkg_resources
@@ -29,16 +32,17 @@ from datetime import datetime
from datetime import timedelta
from time import strftime
-__version__ = '1.0.1'
-#version = '1.0.1'
+__version__ = '1.0.2'
#------------------------------------------------
# Text Coloring
#------------------------------------------------
# Usage: print (yellow("This is yellow"))
def color(text, color_code):
- if sys.platform == "win32" and "xterm" not in os.getenv("TERM"): # [xterm, xterm-color, xterm-256color]
- return text
+
+ # Temporary fix for issue #2
+ #if (sys.platform == "win32") and not ("xterm" in os.getenv("TERM")): # [xterm, xterm-color, xterm-256color]
+ # return text
# for brighter colors, use "1;" in front of "color_code"
bright = '' # '1;'
return '\x1b[%s%sm%s\x1b[0m' % (bright, color_code, text)
@@ -49,7 +53,7 @@ def bgreen(text): return color(text, '1;49;32'); # bright green
def orange(text): return color(text, '0;49;91'); # 31 - Hard to look good! (or remains "red")
def yellow(text): return color(text, 33) #
def blue(text): return color(text, '1;49;34') # bright blue
-def purple(text): return color(text, 35) #
+def purple(text): return color(text, 35) # aka. magenta
def cyan(text): return color(text, '0;49;96') # 36
def white(text): return color(text, '0;49;97'); # bright white
@@ -62,7 +66,7 @@ def print_legend():
print( " {} = Bad / Non-Standard Installation Path".format(purple(cc)) )
print( " {} = Possibly Multiple installations (differing file times)".format(yellow(cc)) )
print( " {} = Recently Changed / Installed (in last 7 days)".format(cyan(cc)) )
- print( " {} = Non-PEM-compliant Version string (PEM-0440) | ~/.local install".format(green(cc)) )
+ print( " {} = Non-PEM-compliant Version string (PEP-0440) | ~/.local install".format(green(cc)) )
print( " {} = A 'setuptools' dependency package".format(blue(cc)) )
#print( " {} = ERROR".format(white(cc)) )
@@ -99,7 +103,7 @@ def pre2txt(pre):
return d[pre]
def is_canonical(version):
- # Check PEM-0440 Version string compliance:
+ # Check PEP-0440 Version string compliance:
# https://www.python.org/dev/peps/pep-0440/
return re.match(r'^([1-9]\d*!)?(0|[1-9]\d*)(\.(0|[1-9]\d*))*((a|b|rc)(0|[1-9]\d*))?(\.post(0|[1-9]\d*))?(\.dev(0|[1-9]\d*))?$', version) is not None
@@ -217,12 +221,8 @@ for d in pkg_resources.working_set :
pkg_loc = test_loc(pkg_loc)
pcnt += 1
- ##pkg += ["{:20} {:<20} {:<20} {:<16} {:<6} {:3}".format(pkg_name.ljust(20,' '),pkg_ctime,pkg_mtime,pkg_ver,pkg_ins,pkg_pre) ]
- #pkg += ["{:20} {:<20} {:<20} {:<16} {:6} {:3} {:<5}".format(pkg_name.ljust(20,' '),pkg_ctime,pkg_mtime,pkg_ver,pkg_ins,pkg_pre,pkg_typ) ]
pkg += ["{:20} {:<20} {:<20} {:<16} {:6} {:<4} {:5} {:3}".format(pkg_name.ljust(20,' '),pkg_ctime,pkg_mtime,pkg_ver,pkg_ins,pkg_pre,pkg_typ,pkg_loc) ]
-##header_str = "{:20} {:20} {:20} {:16} {:6} {:3}".format('Package'.ljust(20, ' '), 'Installed (cTime)', 'Modified (mTime)', 'Version', 'Type', 'Prec')
-#header_str = "{:20} {:20} {:20} {:16} {:6} {:3} {:5}".format('Package'.ljust(20, ' '), 'Installed (cTime)', 'Modified (mTime)', 'Version', 'Inst', 'Prec', 'Type')
header_str = "{:20} {:20} {:20} {:16} {:6} {:4} {:5} {:3}".format('Package'.ljust(20, ' '), 'Installed (cTime)', 'Modified (mTime)', 'Version', 'Inst', 'Prec', 'Type ', 'Loc')
hlen = len(header_str)
@@ -230,7 +230,7 @@ print('\n' + header_str)
print("-"*hlen)
spkg = sorted(pkg, key=str.lower)
-spkg = pkgcol(spkg) # set color to pkg_name
+spkg = pkgcol(spkg)
print('\n'.join(spkg))
print("-"*hlen)
diff --git a/pip-describe b/pip-describe
new file mode 100755
index 0000000..4004fe5
--- /dev/null
+++ b/pip-describe
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# pip-describe - Show full text package description from PyPI
+# -*- coding: utf-8 -*-
+#----------------------------------------------------------------------
+# File Name : pip-describe
+# Author : E:V:A
+# Last Modified : 2018-12-01
+# Version : 1.0.0
+# License : GPLv3
+# URL : https://github.com/E3V3A/pip-date
+#----------------------------------------------------------------------
+# NOTE: We don't do the summary as it is already available
+# from the `pip search` results.
+# [ ] But we can always add CLI switch `-s` for summary
+#----------------------------------------------------------------------
+import sys
+#import requests as req
+
+try:
+ import requests as req
+except ModuleNotFoundError as err:
+ print("\nThis program need the \"requests\" package to work.")
+ print("Please download and install from:\nhttps://github.com/requests/requests")
+ print(err)
+ sys.exit(1)
+
+__version__ = '1.0.0'
+
+def usage() :
+ print("\n Usage: %s \n" % sys.argv[0])
+ print(" This will return the full-text package description (usually the README)")
+ print(" as found on PyPI, for any given .\n")
+ print(" This script is part of the pip-date package at:")
+ print(" https://github.com/E3V3A/pip-date/\n")
+ sys.exit(2)
+
+narg = len(sys.argv) - 1
+if narg == 1:
+ pkg = sys.argv[1]
+else:
+ usage()
+
+url = 'https://pypi.org/pypi/%s/json' % pkg
+res = req.get(url)
+if res.status_code == 200:
+ dat = res.json()
+ #smm = dat['info']['summary'].strip() # (short) description
+ des = dat['info']['description'].strip() # long_description (often full README)
+ print("\nPackage Description:")
+ print("-"*80)
+ print("%s" % des)
+ print("-"*80)
+else:
+ print('\nERROR (%s): Package \"%s\" doesn\'t exist!' % (res.status_code,pkg))
+ sys.exit(2)
diff --git a/pyOSinfo b/pyOSinfo
new file mode 100755
index 0000000..e53e354
--- /dev/null
+++ b/pyOSinfo
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# pyOSinfo - Show what Python3 thinks about your system environment
+# -*- coding: utf-8 -*-
+#----------------------------------------------------------------------
+# File Name : pyOSinfo
+# Author : E:V:A
+# Last Modified : 2018-12-01
+# Version : 1.0.0
+# License : GPLv3
+# URL : https://github.com/E3V3A/pip-date/
+# Description : Show some system, os and platform information as seen by python3
+#----------------------------------------------------------------------
+import os, sys, platform, site
+from os.path import join
+
+__version__ = '1.0.0'
+
+TRUECOLOR = "\x1b[38;2;255;100;0mTRUECOLOR\x1b[0m"
+
+print("\nCurrent OS variables as seen by Python3 (%s)\n" % platform.python_version() )
+print('os.getenv(\"TERM\"): %s' % os.getenv("TERM")) # [xterm, xterm-color, xterm-256color]
+print('os.name: %s' % os.name ) # [posix, nt, java]
+print('os.sys.platform: %s' % os.sys.platform ) # [linux, win32, cygwin, darwin]
+print('sys.platform: %s' % sys.platform ) # [linux, win32, cygwin, darwin]
+print('TRUECOLOR (orange): %s' % TRUECOLOR ) # TRUECOLOR written in nice orange
+
+print('\nos.uname:') # sysname, nodename, release, version, machine
+print('\tnodename: %s' % os.uname()[1] ) #
+print('\tmachine: %s' % os.uname()[4] ) #
+print('\tsysname: %s' % os.uname()[0] ) #
+print('\trelease: %s' % os.uname()[2] ) #
+print('\tversion: %s' % os.uname()[3] ) #
+
+print('\nplatform:')
+print('\tnode: %s' % platform.node() )
+print('\tmachine: %s' % platform.machine() )
+print('\tprocessor: %s' % platform.processor() )
+print('\tsystem: %s' % platform.system() )
+print('\trelease: %s' % platform.release() )
+print('\tversion: %s' % platform.version() )
+print('\tplatform: %s' % platform.platform() )
+print('\n\tuname (6): (%s,%s,%s,%s,%s,%s)' % platform.uname() ) # (system, node, release, version, machine, processor)
+print('\tarchitecture (2): (%s,%s)' % platform.architecture() ) # (bits, linkage)
+#print('\twin32_ver (4): (%s,%s,%s,%s)' % platform.win32_ver() ) # (release, version, csd, ptype)
+
+print("\nsite:")
+print("\tgetsitepackages[0]: %s" % site.getsitepackages()[0])
+print("\tPREFIXES (2): %s" % site.PREFIXES)
+print("\tUSER_SITE: %s" % site.USER_SITE)
+print("\tUSER_BASE: %s" % site.USER_BASE)
+
+print('\nsys.path:\n\t%s\n' % ('\n\t'.join(sys.path)) )
+
+sys.exit(0)
diff --git a/pyfileinfo b/pyfileinfo
new file mode 100755
index 0000000..93b3523
--- /dev/null
+++ b/pyfileinfo
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# pyfileinfo - Get detailed file info from "stat" of file
+# -*- coding: utf-8 -*-
+#----------------------------------------------------------------------
+# File Name : pyfileinfo
+# Author : E:V:A
+# Last Modified : 2018-12-01
+# Version : 1.1.0
+# License : GPLv3
+# URL : https://github.com/E3V3A/pip-date
+# Description : Show detailed file information for a given file using python's os.stat info
+#
+# References:
+# [1] https://linuxhandbook.com/file-timestamps/
+# [2] https://www.unixtutorial.org/atime-ctime-mtime-in-unix-filesystems/
+#----------------------------------------------------------------------
+import os, sys, stat, platform
+import time, getopt
+
+__version__ = '1.1.0'
+
+#------------------------------------------------
+# Helper Functions
+#------------------------------------------------
+def usage() :
+ print("\nUsage: %s " % sys.argv[0])
+ print("\nOptions:")
+ print(" -c : For License/Copyright info")
+ print(" -h, --help : For this help ")
+ print(" -v, --version : For Version info")
+ sys.exit()
+
+def copyright():
+ print("\nProgram License: GPLv3\nMaintenance URL: https://github.com/E3V3A/pip-date")
+ sys.exit()
+
+def pversion():
+ print("\nVersion: %s" % __version__)
+ sys.exit()
+
+def print_legend():
+ print("\nThe tuple items have the following meanings:")
+ print(" st_mode: : protection bits")
+ print(" st_ino : inode number")
+ print(" st_dev : device")
+ print(" st_nlink : number of hard links")
+ print(" st_uid : user ID of owner")
+ print(" st_gid : group ID of owner")
+ print(" st_size : file size (bytes)")
+ print(" st_atime : last access time (seconds since epoch)")
+ print(" st_mtime : last modification time")
+ print(" st_ctime : time of: \"creation\" for Linux / \"change\" for Windows")
+ print()
+
+#------------------------------------------------
+# CLI arguments
+#------------------------------------------------
+narg = len(sys.argv) - 1
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], ":hvc", ["help", "version"])
+except getopt.GetoptError :
+ usage()
+ sys.exit(2)
+
+if not opts:
+ if not args or narg > 1:
+ usage();
+ sys.exit();
+ elif narg == 1:
+ filename = args[0]
+else:
+ for opt, arg in opts:
+ if opt in ("-h", "--help"): usage();
+ elif opt in ("-v", "--version"): pversion();
+ elif opt == "-c": copyright();
+
+#------------------------------------------------
+# MAIN
+#------------------------------------------------
+if platform.architecture()[1] == "WindowsPE":
+ isWinFS = True
+else:
+ isWinFS = False
+
+try:
+ fhand = open(filename)
+except IsADirectoryError as e:
+ print ("ERROR: %s" % e)
+ sys.exit(2)
+
+count = 0
+for lines in fhand:
+ count = count + 1
+
+fdata = open(filename).read()
+t_char = len(fdata)
+
+try:
+ file_stats = os.stat(filename)
+ print ("\nThe os.stat() tuple:\n")
+ print (file_stats)
+ print_legend()
+
+except OSError:
+ print ("\nNameError : [%s] No such file or directory\n", filename)
+ sys.exit(2)
+
+file_info = {
+ 'fname': filename,
+ 'fsize': file_stats[stat.ST_SIZE],
+ 'no_of_lines':count,
+ 't_char':t_char,
+ 'f_lm' : time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(file_stats[stat.ST_MTIME])),
+ 'f_la' : time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(file_stats[stat.ST_ATIME])),
+ 'f_ct' : time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(file_stats[stat.ST_CTIME])),
+}
+
+print (" File Name : ", file_info['fname'])
+print (" File Type : ", "directory" if stat.S_ISDIR(file_stats[stat.ST_MODE]) else "\"normal\" file")
+print (" File Size : ", file_info['fsize'] , " (bytes)")
+print (" Total Lines : ", file_info['no_of_lines'])
+print (" Total Chars : ", file_info['t_char'])
+print()
+
+if isWinFS:
+ # powershell.exe -Command "Get-Item CHANGES.txt | Format-List"
+ # Poweshell: .CreationTime = .LastAccessTime
+ # Poweshell: .LastWriteTime
+ print("Using WindowsPE")
+ print (" ctime: OS change time : ", file_info['f_ct'], " (PS: n/a)")
+ print (" mtime: user modified : ", file_info['f_lm'], " (PS: .LastWriteTime)")
+ print (" atime: creation time : ", file_info['f_la'], " (PS: .CreationTime = .LastAccessTime)")
+else:
+ print("Using a Linux based OS?")
+ print (" ctime: creation time : ", file_info['f_ct'])
+ print (" mtime: last modified : ", file_info['f_lm'])
+ print (" atime: last accessed : ", file_info['f_la'])
+
+sys.exit(0)
diff --git a/setup.py b/setup.py
index 48aef79..4704d36 100644
--- a/setup.py
+++ b/setup.py
@@ -18,20 +18,22 @@ def readme():
setup(
name = 'pip-date',
- version = '1.0.1',
+ version = '1.0.2',
author = 'E:V:A',
author_email = 'xdae3v3a@gmail.com',
- description = 'Show the installation/modification times of all your pip packages',
- long_description = 'A simple Python3 CLI tool to show the installation or modification times of all your pip packages.',
+ description = 'Show the installation/modification times of all your pip packages and other tools',
+ long_description = 'A light CLI tool-set to show the installation or modification times of all your pip packages.',
long_description_content_type='text/plain',
#long_description = readme(),
#long_description_content_type = 'text/markdown',
license='LICENSE.txt',
url = 'https://github.com/e3v3a/pip-date/',
packages = find_packages(),
- #scripts=['pip-date/pip-date', 'pip-date/pipbyday'],
- scripts=['pip-date', 'pipbyday'],
- keywords = 'pip date package setuptools wheel egg',
+ scripts=['pip-date', 'pip-describe', 'pipbyday', 'pyfileinfo', 'pyOSinfo'],
+ keywords = 'pip date package management setuptools wheel egg stat os',
+ install_requires=[
+ 'requests',
+ ],
python_requires = '>=3',
classifiers=[
#'Private :: Do Not Upload',