Skip to content

Commit

Permalink
Package maintenance update with 3 new tools
Browse files Browse the repository at this point in the history
* Fix for issue #2 (windows)
* Fixed UI PEP typo
* Added pip-describe (requests) - get full descriptions of not installed packages
* Added pyOSinfo - to get os,platform info
* Added pyfileinfo - to get python-based stat info
* General code and README cleanup
* Updated color-highlight scheme
  • Loading branch information
E3V3A committed Dec 1, 2018
1 parent ef1a2a9 commit 0c1bf99
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 96 deletions.
108 changes: 37 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 |

---

Expand Down Expand Up @@ -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?*
Expand All @@ -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
Expand All @@ -108,7 +122,7 @@ pip install pip-date
```


**For manual installation:**
**For single file installation:**

```bash
cd /usr/bin/
Expand All @@ -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**
Expand All @@ -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).

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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:!

<sub>I use `GPLv3` because sharing code modifications is more beneficial for the world.</sub>

[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
Expand Down
38 changes: 19 additions & 19 deletions pip-date
Original file line number Diff line number Diff line change
@@ -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()"]
#
Expand All @@ -19,26 +22,27 @@
# - [ ] '-v' : THIS program version
# - [ ] '-t <days>' : To highlight packages installed <days> 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
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)
Expand All @@ -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

Expand All @@ -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)) )

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -217,20 +221,16 @@ 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)

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)
Expand Down
55 changes: 55 additions & 0 deletions pip-describe
Original file line number Diff line number Diff line change
@@ -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 <package-name>\n" % sys.argv[0])
print(" This will return the full-text package description (usually the README)")
print(" as found on PyPI, for any given <package-name>.\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)
54 changes: 54 additions & 0 deletions pyOSinfo
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit 0c1bf99

Please sign in to comment.