Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-identify for openSUSE:Factory 
checked in at 2021-06-24 18:23:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-identify (Old)
 and      /work/SRC/openSUSE:Factory/.python-identify.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-identify"

Thu Jun 24 18:23:00 2021 rev:8 rq:901746 version:2.2.10

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-identify/python-identify.changes  
2020-05-26 17:49:38.747923345 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-identify.new.2625/python-identify.changes    
    2021-06-24 18:23:18.760965370 +0200
@@ -1,0 +2,20 @@
+Thu Jun 24 12:31:47 UTC 2021 - Mark??ta Machov?? <mmach...@suse.com>
+
+- update to 2.2.10
+  * add few file formats
+  * detect WORKSPACE files as bazel
+- stick with older editdistance as it has more functionality
+
+-------------------------------------------------------------------
+Wed May 26 10:19:37 UTC 2021 - pgaj...@suse.com
+
+- version update to 2.2.6
+  * lot of changes, no upstream changelog found
+   https://github.com/pre-commit/identify/compare/v1.4.14...v2.2.6
+
+-------------------------------------------------------------------
+Wed May 26 06:36:52 UTC 2021 - pgaj...@suse.com
+
+- %check: use %pytest macro
+
+-------------------------------------------------------------------

Old:
----
  identify-1.4.14.tar.gz

New:
----
  identify-2.2.10.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-identify.spec ++++++
--- /var/tmp/diff_new_pack.gE5bRM/_old  2021-06-24 18:23:19.084965730 +0200
+++ /var/tmp/diff_new_pack.gE5bRM/_new  2021-06-24 18:23:19.088965734 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-identify
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-identify
-Version:        1.4.14
+Version:        2.2.10
 Release:        0
 Summary:        File identification library for Python
 License:        MIT
@@ -26,13 +26,13 @@
 URL:            https://github.com/chriskuehl/identify
 Source:         
https://github.com/chriskuehl/identify/archive/v%{version}.tar.gz#/identify-%{version}.tar.gz
 BuildRequires:  %{python_module editdistance}
-BuildRequires:  %{python_module pytest-runner}
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-setuptools
 Requires(post): update-alternatives
-Requires(postun): update-alternatives
+Requires(postun):update-alternatives
 Suggests:       python-editdistance
 BuildArch:      noarch
 %python_subpackages
@@ -42,6 +42,9 @@
 
 %prep
 %setup -q -n identify-%{version}
+# stick with editdistance as it generally has more functionality
+sed -i 's/editdistance_s.distance/editdistance.eval/' identify/identify.py
+sed -i 's/editdistance_s/editdistance/' identify/identify.py
 
 %build
 %python_build
@@ -52,7 +55,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py pytest
+%pytest
 
 %post
 %python_install_alternative identify-cli

++++++ identify-1.4.14.tar.gz -> identify-2.2.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/.coveragerc 
new/identify-2.2.10/.coveragerc
--- old/identify-1.4.14/.coveragerc     2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/.coveragerc     1970-01-01 01:00:00.000000000 +0100
@@ -1,29 +0,0 @@
-[run]
-branch = True
-source =
-    .
-omit =
-    .tox/*
-    /usr/*
-    setup.py
-
-[report]
-show_missing = True
-
-exclude_lines =
-    # Have to re-enable the standard pragma
-    \#\s*pragma: no cover
-
-    # Don't complain if tests don't hit defensive assertion code:
-    ^\s*raise AssertionError\b
-    ^\s*raise NotImplementedError\b
-    ^\s*return NotImplemented\b
-    ^\s*raise$
-
-    # Don't complain if non-runnable code isn't run:
-    ^if __name__ == ['"]__main__['"]:$
-
-[html]
-directory = coverage-html
-
-# vim:ft=dosini
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/.github/FUNDING.yml 
new/identify-2.2.10/.github/FUNDING.yml
--- old/identify-1.4.14/.github/FUNDING.yml     1970-01-01 01:00:00.000000000 
+0100
+++ new/identify-2.2.10/.github/FUNDING.yml     2021-06-07 19:18:24.000000000 
+0200
@@ -0,0 +1,2 @@
+github: asottile
+open_collective: pre-commit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/.pre-commit-config.yaml 
new/identify-2.2.10/.pre-commit-config.yaml
--- old/identify-1.4.14/.pre-commit-config.yaml 2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/.pre-commit-config.yaml 2021-06-07 19:18:24.000000000 
+0200
@@ -1,36 +1,45 @@
 repos:
 -   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v2.1.0
+    rev: v4.0.1
     hooks:
-    -   id: trailing-whitespace
-    -   id: end-of-file-fixer
     -   id: check-docstring-first
-    -   id: check-merge-conflict
     -   id: check-yaml
     -   id: debug-statements
     -   id: double-quote-string-fixer
+    -   id: end-of-file-fixer
     -   id: name-tests-test
-    -   id: check-added-large-files
-    -   id: check-byte-order-marker
-    -   id: fix-encoding-pragma
--   repo: https://gitlab.com/pycqa/flake8
-    rev: 3.7.7
+    -   id: requirements-txt-fixer
+    -   id: trailing-whitespace
+-   repo: https://github.com/asottile/setup-cfg-fmt
+    rev: v1.17.0
+    hooks:
+    -   id: setup-cfg-fmt
+-   repo: https://github.com/PyCQA/flake8
+    rev: 3.9.2
     hooks:
     -   id: flake8
         exclude: ^identify/vendor/licenses\.py$
+        additional_dependencies: [flake8-typing-imports==1.10.1]
 -   repo: https://github.com/pre-commit/mirrors-autopep8
-    rev: v1.4.3
+    rev: v1.5.7
     hooks:
     -   id: autopep8
 -   repo: https://github.com/asottile/reorder_python_imports
-    rev: v1.4.0
+    rev: v2.5.0
     hooks:
     -   id: reorder-python-imports
-        args: [
-            '--add-import', 'from __future__ import absolute_import',
-            '--add-import', 'from __future__ import unicode_literals',
-        ]
+        args: [--py3-plus]
 -   repo: https://github.com/asottile/add-trailing-comma
-    rev: v1.0.0
+    rev: v2.1.0
     hooks:
     -   id: add-trailing-comma
+        args: [--py36-plus]
+-   repo: https://github.com/asottile/pyupgrade
+    rev: v2.19.0
+    hooks:
+    -   id: pyupgrade
+        args: [--py36-plus]
+-   repo: https://github.com/pre-commit/mirrors-mypy
+    rev: v0.812
+    hooks:
+    -   id: mypy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/.travis.yml 
new/identify-2.2.10/.travis.yml
--- old/identify-1.4.14/.travis.yml     2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/.travis.yml     1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-language: python
-matrix:
-    include:
-        -   env: TOXENV=py27
-        -   env: TOXENV=py35
-            python: 3.5
-        -   env: TOXENV=py36
-            python: 3.6
-        -   env: TOXENV=pypy
-            python: pypy
-install: pip install coveralls tox
-script: tox
-after_success: coveralls
-cache:
-    directories:
-        - $HOME/.cache/pip
-        - $HOME/.cache/pre-commit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/Makefile new/identify-2.2.10/Makefile
--- old/identify-1.4.14/Makefile        2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/Makefile        1970-01-01 01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-.PHONY: minimal
-minimal: venv
-
-venv: setup.py requirements-dev.txt tox.ini
-       tox -e venv
-
-.PHONY: test
-test:
-       tox
-
-.PHONY: clean
-clean:
-       find -name '*.pyc' -delete
-       find -name '__pycache__' -delete
-       rm -rf .tox
-       rm -rf venv
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/README.md 
new/identify-2.2.10/README.md
--- old/identify-1.4.14/README.md       2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/README.md       2021-06-07 19:18:24.000000000 +0200
@@ -1,8 +1,9 @@
 identify
 ========
 
-[![Build 
Status](https://travis-ci.org/chriskuehl/identify.svg?branch=master)](https://travis-ci.org/chriskuehl/identify)
-[![Coverage 
Status](https://coveralls.io/repos/github/chriskuehl/identify/badge.svg?branch=master)](https://coveralls.io/github/chriskuehl/identify?branch=master)
+[![Build 
Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.identify?branchName=master)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=67&branchName=master)
+[![Azure DevOps 
coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/67/master.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=67&branchName=master)
+[![pre-commit.ci 
status](https://results.pre-commit.ci/badge/github/pre-commit/identify/master.svg)](https://results.pre-commit.ci/latest/github/pre-commit/identify/master)
 [![PyPI 
version](https://badge.fury.io/py/identify.svg)](https://pypi.python.org/pypi/identify)
 
 File identification library for Python.
@@ -21,6 +22,7 @@
 (a superset of all other methods):
 
 ```python
+>>> from identify import identify
 >>> identify.tags_from_path('/path/to/file.py')
 {'file', 'text', 'python', 'non-executable'}
 >>> identify.tags_from_path('/path/to/file-with-shebang')
@@ -35,7 +37,7 @@
 
 When using a file on disk, the checks performed are:
 
-* File type (file, symlink, directory)
+* File type (file, symlink, directory, socket)
 * Mode (is it executable?)
 * File name (mostly based on extension)
 * If executable, the shebang is read and the interpreter interpreted
@@ -74,11 +76,11 @@
   --filename-only
 ```
 
-```bash
+```console
 $ identify-cli setup.py; echo $?
 ["file", "non-executable", "python", "text"]
 0
-identify setup.py --filename-only; echo $?
+$ identify setup.py --filename-only; echo $?
 ["python", "text"]
 0
 $ identify-cli wat.wat; echo $?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/azure-pipelines.yml 
new/identify-2.2.10/azure-pipelines.yml
--- old/identify-1.4.14/azure-pipelines.yml     1970-01-01 01:00:00.000000000 
+0100
+++ new/identify-2.2.10/azure-pipelines.yml     2021-06-07 19:18:24.000000000 
+0200
@@ -0,0 +1,19 @@
+trigger:
+  branches:
+    include: [master, test-me-*]
+  tags:
+    include: ['*']
+
+resources:
+  repositories:
+    - repository: asottile
+      type: github
+      endpoint: github
+      name: asottile/azure-pipeline-templates
+      ref: refs/tags/v2.1.0
+
+jobs:
+- template: job--python-tox.yml@asottile
+  parameters:
+    toxenvs: [pypy3, py36, py37, py38]
+    os: linux
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/bin/vendor-licenses 
new/identify-2.2.10/bin/vendor-licenses
--- old/identify-1.4.14/bin/vendor-licenses     2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/bin/vendor-licenses     2021-06-07 19:18:24.000000000 
+0200
@@ -1,19 +1,15 @@
 #!/usr/bin/env python3
-# -*- coding: utf-8 -*-
 """Usage:
 
     ./bin/vendor-licenses > identify/vendor/licenses.py
 """
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 import argparse
 import os.path
 import subprocess
 import tempfile
 
 
-def main():
+def main() -> int:
     parser = argparse.ArgumentParser()
     parser.add_argument('--revision', default='HEAD')
     args = parser.parse_args()
@@ -37,26 +33,24 @@
 
             _, data, license_text = contents.split('---\n', 2)
 
-            spdx, = [
+            spdx, = (
                 line[len('spdx-id:'):].strip()
                 for line in data.splitlines()
                 if line.startswith('spdx-id:')
-            ]
+            )
 
             licenses.append((spdx, license_text))
 
-        print('# -*- coding: utf-8 -*-')
-        print('from __future__ import absolute_import')
-        print('from __future__ import unicode_literals')
         print('LICENSES = (')
         for spdx, text in sorted(licenses):
             print('    (')
-            print('        {!r},'.format(spdx))
+            print(f'        {spdx!r},')
             print("        '''\\")
             print(text.replace('\t', '    ').replace(' \n', '').strip())
             print("''',")
             print('    ),')
         print(')')
+    return 0
 
 
 if __name__ == '__main__':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/identify/cli.py 
new/identify-2.2.10/identify/cli.py
--- old/identify-1.4.14/identify/cli.py 2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/identify/cli.py 2021-06-07 19:18:24.000000000 +0200
@@ -1,14 +1,12 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 import argparse
 import json
+from typing import Optional
+from typing import Sequence
 
 from identify import identify
 
 
-def main(argv=None):
+def main(argv: Optional[Sequence[str]] = None) -> int:
     parser = argparse.ArgumentParser()
     parser.add_argument('--filename-only', action='store_true')
     parser.add_argument('path')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/identify/extensions.py 
new/identify-2.2.10/identify/extensions.py
--- old/identify-1.4.14/identify/extensions.py  2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/identify/extensions.py  2021-06-07 19:18:24.000000000 
+0200
@@ -1,21 +1,23 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
-
 EXTENSIONS = {
     'adoc': {'text', 'asciidoc'},
     'asciidoc': {'text', 'asciidoc'},
     'apinotes': {'text', 'apinotes'},
     'asar': {'binary', 'asar'},
+    'avif': {'binary', 'image', 'avif'},
     'bash': {'text', 'shell', 'bash'},
     'bat': {'text', 'batch'},
+    'bats': {'text', 'shell', 'bash', 'bats'},
+    'bib': {'text', 'bib'},
     'bmp': {'binary', 'image', 'bitmap'},
     'bz2': {'binary', 'bzip2'},
+    'bzl': {'text', 'bazel'},
     'c': {'text', 'c'},
     'cc': {'text', 'c++'},
-    'cu': {'text', 'cuda'},
     'cfg': {'text'},
+    'chs': {'text', 'c2hs'},
+    'clj': {'text', 'clojure'},
+    'cljc': {'text', 'clojure'},
+    'cljs': {'text', 'clojure', 'clojurescript'},
     'cmake': {'text', 'cmake'},
     'cnf': {'text'},
     'coffee': {'text', 'coffee'},
@@ -23,14 +25,20 @@
     'cpp': {'text', 'c++'},
     'crt': {'text', 'pem'},
     'cs': {'text', 'c#'},
+    'csproj': {'text', 'xml', 'csproj'},
+    'csh': {'text', 'shell', 'csh'},
     'cson': {'text', 'cson'},
     'css': {'text', 'css'},
     'csv': {'text', 'csv'},
+    'cu': {'text', 'cuda'},
+    'cuh': {'text', 'cuda'},
     'cxx': {'text', 'c++'},
     'dart': {'text', 'dart'},
     'def': {'text', 'def'},
+    'dll': {'binary'},
     'dtd': {'text', 'dtd'},
     'ear': {'binary', 'zip', 'jar'},
+    'edn': {'text', 'clojure', 'edn'},
     'ejs': {'text', 'ejs'},
     'eot': {'binary', 'eot'},
     'eps': {'binary', 'eps'},
@@ -39,11 +47,13 @@
     'eyaml': {'text', 'yaml'},
     'feature': {'text', 'gherkin'},
     'fish': {'text', 'fish'},
+    'gd': {'text', 'gdscript'},
     'gemspec': {'text', 'ruby'},
     'gif': {'binary', 'image', 'gif'},
     'go': {'text', 'go'},
     'gotmpl': {'text', 'gotmpl'},
     'gpx': {'text', 'gpx', 'xml'},
+    'graphql': {'text', 'graphql'},
     'gradle': {'text', 'groovy'},
     'groovy': {'text', 'groovy'},
     'gyb': {'text', 'gyb'},
@@ -51,7 +61,9 @@
     'gypi': {'text', 'gyp', 'python'},
     'gz': {'binary', 'gzip'},
     'h': {'text', 'header', 'c', 'c++'},
+    'hh': {'text', 'header', 'c++'},
     'hpp': {'text', 'header', 'c++'},
+    'hs': {'text', 'haskell'},
     'htm': {'text', 'html'},
     'html': {'text', 'html'},
     'hxx': {'text', 'header', 'c++'},
@@ -62,11 +74,14 @@
     'idr': {'text', 'idris'},
     'inc': {'text', 'inc'},
     'ini': {'text', 'ini'},
+    'inx': {'text', 'xml', 'inx'},
+    'ipynb': {'text', 'jupyter'},
     'j2': {'text', 'jinja'},
     'jade': {'text', 'jade'},
     'jar': {'binary', 'zip', 'jar'},
     'java': {'text', 'java'},
-    'jenkinsfile': {'text', 'groovy'},
+    'jenkins': {'text', 'groovy', 'jenkins'},
+    'jenkinsfile': {'text', 'groovy', 'jenkins'},
     'jinja': {'text', 'jinja'},
     'jinja2': {'text', 'jinja'},
     'jpeg': {'binary', 'image', 'jpeg'},
@@ -78,18 +93,27 @@
     'key': {'text', 'pem'},
     'kml': {'text', 'kml', 'xml'},
     'kt': {'text', 'kotlin'},
+    'lean': {'text', 'lean'},
+    'lektorproject': {'text', 'ini', 'lektorproject'},
     'less': {'text', 'less'},
+    'lhs': {'text', 'literate-haskell'},
+    'libsonnet': {'text', 'jsonnet'},
     'lidr': {'text', 'idris'},
+    'lr': {'text', 'lektor'},
     'lua': {'text', 'lua'},
     'm': {'text', 'c', 'objective-c'},
     'manifest': {'text', 'manifest'},
     'map': {'text', 'map'},
     'markdown': {'text', 'markdown'},
     'md': {'text', 'markdown'},
+    'mdx': {'text', 'mdx'},
     'mib': {'text', 'mib'},
     'mk': {'text', 'makefile'},
+    'ml': {'text', 'ocaml'},
+    'mli': {'text', 'ocaml'},
     'mm': {'text', 'c++', 'objective-c++'},
     'modulemap': {'text', 'modulemap'},
+    'myst': {'text', 'myst'},
     'ngdoc': {'text', 'ngdoc'},
     'nim': {'text', 'nim'},
     'nims': {'text', 'nim'},
@@ -114,54 +138,76 @@
     'proto': {'text', 'proto'},
     'puml': {'text', 'plantuml'},
     'purs': {'text', 'purescript'},
+    'pxd': {'text', 'cython'},
+    'pxi': {'text', 'cython'},
     'py': {'text', 'python'},
     'pyi': {'text', 'pyi'},
+    'pyproj': {'text', 'xml', 'pyproj'},
     'pyx': {'text', 'cython'},
-    'pxd': {'text', 'cython'},
-    'pxi': {'text', 'cython'},
+    'pyz': {'binary', 'pyz'},
+    'pyzw': {'binary', 'pyz'},
     'r': {'text', 'r'},
+    'rake': {'text', 'ruby'},
     'rb': {'text', 'ruby'},
     'rs': {'text', 'rust'},
     'rst': {'text', 'rst'},
     's': {'text', 'asm'},
+    'sass': {'text', 'sass'},
     'sbt': {'text', 'sbt', 'scala'},
     'sc': {'text', 'scala'},
     'scala': {'text', 'scala'},
-    'scss': {'text', 'scss'},
     'scm': {'text', 'scheme'},
+    'scss': {'text', 'scss'},
     'sh': {'text', 'shell'},
+    'sln': {'text', 'sln'},
     'sls': {'text', 'salt'},
     'so': {'binary'},
     'sol': {'text', 'solidity'},
     'spec': {'text', 'spec'},
+    'sql': {'text', 'sql'},
     'ss': {'text', 'scheme'},
     'styl': {'text', 'stylus'},
-    'sql': {'text', 'sql'},
-    'svg': {'text', 'image', 'svg'},
+    'sv': {'text', 'system-verilog'},
+    'svg': {'text', 'image', 'svg', 'xml'},
+    'svh': {'text', 'system-verilog'},
     'swf': {'binary', 'swf'},
     'swift': {'text', 'swift'},
     'swiftdeps': {'text', 'swiftdeps'},
     'tac': {'text', 'twisted', 'python'},
     'tar': {'binary', 'tar'},
+    'tex': {'text', 'tex'},
+    'tf': {'text', 'terraform'},
+    'tfvars': {'text', 'terraform'},
     'tgz': {'binary', 'gzip'},
     'thrift': {'text', 'thrift'},
     'tiff': {'binary', 'image', 'tiff'},
     'toml': {'text', 'toml'},
-    'tf': {'text', 'terraform'},
     'ts': {'text', 'ts'},
+    'tsv': {'text', 'tsv'},
     'tsx': {'text', 'tsx'},
     'ttf': {'binary', 'ttf'},
+    'twig': {'text', 'twig'},
+    'txsprofile': {'text', 'ini', 'txsprofile'},
     'txt': {'text', 'plain-text'},
+    'urdf': {'text', 'xml', 'urdf'},
+    'v': {'text', 'verilog'},
+    'vb': {'text', 'vb'},
+    'vbproj': {'text', 'xml', 'vbproj'},
+    'vcxproj': {'text', 'xml', 'vcxproj'},
     'vdx': {'text', 'vdx'},
+    'vh': {'text', 'verilog'},
+    'vhd': {'text', 'vhdl'},
     'vim': {'text', 'vim'},
     'vue': {'text', 'vue'},
     'war': {'binary', 'zip', 'jar'},
     'wav': {'binary', 'audio', 'wav'},
-    'wkt': {'text', 'wkt'},
+    'webp': {'binary', 'image', 'webp'},
     'whl': {'binary', 'wheel', 'zip'},
+    'wkt': {'text', 'wkt'},
     'woff': {'binary', 'woff'},
     'woff2': {'binary', 'woff2'},
     'wsgi': {'text', 'wsgi', 'python'},
+    'xhtml': {'text', 'xml', 'html', 'xhtml'},
     'xml': {'text', 'xml'},
     'xq': {'text', 'xquery'},
     'xql': {'text', 'xquery'},
@@ -175,8 +221,10 @@
     'yang': {'text', 'yang'},
     'yin': {'text', 'xml', 'yin'},
     'yml': {'text', 'yaml'},
+    'zcml': {'text', 'xml', 'zcml'},
     'zig': {'text', 'zig'},
     'zip': {'binary', 'zip'},
+    'zpt': {'text', 'zpt'},
     'zsh': {'text', 'shell', 'zsh'},
 }
 EXTENSIONS_NEED_BINARY_CHECK = {
@@ -185,42 +233,65 @@
 
 NAMES = {
     '.babelrc': EXTENSIONS['json'] | {'babelrc'},
-    '.bashrc': EXTENSIONS['bash'],
     '.bash_aliases': EXTENSIONS['bash'],
     '.bash_profile': EXTENSIONS['bash'],
+    '.bashrc': EXTENSIONS['bash'],
+    '.bazelrc': {'text', 'bazelrc'},
     '.bowerrc': EXTENSIONS['json'] | {'bowerrc'},
+    '.browserslistrc': {'text', 'browserslistrc'},
+    '.clang-format': EXTENSIONS['yaml'],
+    '.clang-tidy': EXTENSIONS['yaml'],
+    '.codespellrc': EXTENSIONS['ini'] | {'codespellrc'},
     '.coveragerc': EXTENSIONS['ini'] | {'coveragerc'},
+    '.cshrc': EXTENSIONS['csh'],
+    '.csslintrc': EXTENSIONS['json'] | {'csslintrc'},
     '.dockerignore': {'text', 'dockerignore'},
     '.editorconfig': {'text', 'editorconfig'},
-    '.gitconfig': EXTENSIONS['ini'] | {'gitconfig'},
-    '.hgrc': EXTENSIONS['ini'] | {'hgrc'},
+    '.flake8': EXTENSIONS['ini'] | {'flake8'},
     '.gitattributes': {'text', 'gitattributes'},
+    '.gitconfig': EXTENSIONS['ini'] | {'gitconfig'},
     '.gitignore': {'text', 'gitignore'},
+    '.gitlint': EXTENSIONS['ini'] | {'gitlint'},
     '.gitmodules': {'text', 'gitmodules'},
+    '.hgrc': EXTENSIONS['ini'] | {'hgrc'},
     '.jshintrc': EXTENSIONS['json'] | {'jshintrc'},
     '.mailmap': {'text', 'mailmap'},
     '.mention-bot': EXTENSIONS['json'] | {'mention-bot'},
     '.npmignore': {'text', 'npmignore'},
     '.pdbrc': EXTENSIONS['py'] | {'pdbrc'},
     '.pypirc': EXTENSIONS['ini'] | {'pypirc'},
+    '.rstcheck.cfg': EXTENSIONS['ini'],
     '.yamllint': EXTENSIONS['yaml'] | {'yamllint'},
+    '.zlogin': EXTENSIONS['zsh'],
+    '.zlogout': EXTENSIONS['zsh'],
+    '.zprofile': EXTENSIONS['zsh'],
     '.zshrc': EXTENSIONS['zsh'],
+    '.zshenv': EXTENSIONS['zsh'],
     'AUTHORS': EXTENSIONS['txt'],
-    'BUILD.bazel': {'text', 'bazel'},
-    'BUILD': {'text', 'bazel'},
+    'BUILD': EXTENSIONS['bzl'],
+    'BUILD.bazel': EXTENSIONS['bzl'],
     'CMakeLists.txt': EXTENSIONS['cmake'],
+    'CHANGELOG': EXTENSIONS['txt'],
+    'CONTRIBUTING': EXTENSIONS['txt'],
     'COPYING': EXTENSIONS['txt'],
     'Dockerfile': {'text', 'dockerfile'},
     'Gemfile': EXTENSIONS['rb'],
-    'Jenkinsfile': {'text', 'groovy'},
+    'Gemfile.lock': {'text'},
+    'GNUmakefile': EXTENSIONS['mk'],
+    'Jenkinsfile': EXTENSIONS['jenkins'],
     'LICENSE': EXTENSIONS['txt'],
     'MAINTAINERS': EXTENSIONS['txt'],
     'Makefile': EXTENSIONS['mk'],
+    'makefile': EXTENSIONS['mk'],
+    'NEWS': EXTENSIONS['txt'],
     'NOTICE': EXTENSIONS['txt'],
     'PATENTS': EXTENSIONS['txt'],
     'Pipfile': EXTENSIONS['toml'],
     'Pipfile.lock': EXTENSIONS['json'],
+    'PKGBUILD': {'text', 'bash', 'pkgbuild', 'alpm'},
+    'pylintrc': EXTENSIONS['ini'] | {'pylintrc'},
     'README': EXTENSIONS['txt'],
     'Rakefile': EXTENSIONS['rb'],
     'setup.cfg': EXTENSIONS['ini'],
+    'WORKSPACE': EXTENSIONS['bzl'],
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/identify/identify.py 
new/identify-2.2.10/identify/identify.py
--- old/identify-1.4.14/identify/identify.py    2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/identify/identify.py    2021-06-07 19:18:24.000000000 
+0200
@@ -1,14 +1,15 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import unicode_literals
-
-import io
+import errno
 import os.path
 import re
 import shlex
+import stat
 import string
 import sys
+from typing import IO
+from typing import List
+from typing import Optional
+from typing import Set
+from typing import Tuple
 
 from identify import extensions
 from identify import interpreters
@@ -19,27 +20,37 @@
 
 DIRECTORY = 'directory'
 SYMLINK = 'symlink'
+SOCKET = 'socket'
 FILE = 'file'
 EXECUTABLE = 'executable'
 NON_EXECUTABLE = 'non-executable'
 TEXT = 'text'
 BINARY = 'binary'
 
-ALL_TAGS = {DIRECTORY, SYMLINK, FILE, EXECUTABLE, NON_EXECUTABLE, TEXT, BINARY}
-ALL_TAGS.update(*extensions.EXTENSIONS.values())
-ALL_TAGS.update(*extensions.EXTENSIONS_NEED_BINARY_CHECK.values())
-ALL_TAGS.update(*extensions.NAMES.values())
-ALL_TAGS.update(*interpreters.INTERPRETERS.values())
-ALL_TAGS = frozenset(ALL_TAGS)
+TYPE_TAGS = frozenset((DIRECTORY, FILE, SYMLINK, SOCKET))
+MODE_TAGS = frozenset((EXECUTABLE, NON_EXECUTABLE))
+ENCODING_TAGS = frozenset((BINARY, TEXT))
+_ALL_TAGS = {*TYPE_TAGS, *MODE_TAGS, *ENCODING_TAGS}
+_ALL_TAGS.update(*extensions.EXTENSIONS.values())
+_ALL_TAGS.update(*extensions.EXTENSIONS_NEED_BINARY_CHECK.values())
+_ALL_TAGS.update(*extensions.NAMES.values())
+_ALL_TAGS.update(*interpreters.INTERPRETERS.values())
+ALL_TAGS = frozenset(_ALL_TAGS)
 
 
-def tags_from_path(path):
-    if not os.path.lexists(path):
-        raise ValueError('{} does not exist.'.format(path))
-    if os.path.isdir(path):
+def tags_from_path(path: str) -> Set[str]:
+    try:
+        sr = os.lstat(path)
+    except (OSError, ValueError):  # same error-handling as `os.lexists()`
+        raise ValueError(f'{path} does not exist.')
+
+    mode = sr.st_mode
+    if stat.S_ISDIR(mode):
         return {DIRECTORY}
-    if os.path.islink(path):
+    if stat.S_ISLNK(mode):
         return {SYMLINK}
+    if stat.S_ISSOCK(mode):
+        return {SOCKET}
 
     tags = {FILE}
 
@@ -62,19 +73,19 @@
 
     # some extensions can be both binary and text
     # see EXTENSIONS_NEED_BINARY_CHECK
-    if not {TEXT, BINARY} & tags:
+    if not ENCODING_TAGS & tags:
         if file_is_text(path):
             tags.add(TEXT)
         else:
             tags.add(BINARY)
 
-    assert {TEXT, BINARY} & tags, tags
-    assert {EXECUTABLE, NON_EXECUTABLE} & tags, tags
+    assert ENCODING_TAGS & tags, tags
+    assert MODE_TAGS & tags, tags
     return tags
 
 
-def tags_from_filename(filename):
-    _, filename = os.path.split(filename)
+def tags_from_filename(path: str) -> Set[str]:
+    _, filename = os.path.split(path)
     _, ext = os.path.splitext(filename)
 
     ret = set()
@@ -95,7 +106,7 @@
     return ret
 
 
-def tags_from_interpreter(interpreter):
+def tags_from_interpreter(interpreter: str) -> Set[str]:
     _, _, interpreter = interpreter.rpartition('/')
 
     # Try "python3.5.2" => "python3.5" => "python3" until one matches.
@@ -108,7 +119,7 @@
     return set()
 
 
-def is_text(bytesio):
+def is_text(bytesio: IO[bytes]) -> bool:
     """Return whether the first KB of contents seems to be binary.
 
     This is roughly based on libmagic's binary/text detection:
@@ -122,14 +133,14 @@
     return not bool(bytesio.read(1024).translate(None, text_chars))
 
 
-def file_is_text(path):
+def file_is_text(path: str) -> bool:
     if not os.path.lexists(path):
-        raise ValueError('{} does not exist.'.format(path))
+        raise ValueError(f'{path} does not exist.')
     with open(path, 'rb') as f:
         return is_text(f)
 
 
-def _shebang_split(line):
+def _shebang_split(line: str) -> List[str]:
     try:
         # shebangs aren't supposed to be quoted, though some tools such as
         # setuptools will write them with quotes so we'll best-guess parse
@@ -141,13 +152,37 @@
         return line.split()
 
 
-def parse_shebang(bytesio):
+def _parse_nix_shebang(
+        bytesio: IO[bytes],
+        cmd: Tuple[str, ...],
+) -> Tuple[str, ...]:
+    while bytesio.read(2) == b'#!':
+        next_line_b = bytesio.readline()
+        try:
+            next_line = next_line_b.decode('UTF-8')
+        except UnicodeDecodeError:
+            return cmd
+
+        for c in next_line:
+            if c not in printable:
+                return cmd
+
+        line_tokens = tuple(_shebang_split(next_line.strip()))
+        for i, token in enumerate(line_tokens[:-1]):
+            if token != '-i':
+                continue
+            # the argument to -i flag
+            cmd = (line_tokens[i + 1],)
+    return cmd
+
+
+def parse_shebang(bytesio: IO[bytes]) -> Tuple[str, ...]:
     """Parse the shebang from a file opened for reading binary."""
     if bytesio.read(2) != b'#!':
         return ()
-    first_line = bytesio.readline()
+    first_line_b = bytesio.readline()
     try:
-        first_line = first_line.decode('UTF-8')
+        first_line = first_line_b.decode('UTF-8')
     except UnicodeDecodeError:
         return ()
 
@@ -159,31 +194,39 @@
     cmd = tuple(_shebang_split(first_line.strip()))
     if cmd and cmd[0] == '/usr/bin/env':
         cmd = cmd[1:]
+        if cmd == ('nix-shell',):
+            return _parse_nix_shebang(bytesio, cmd)
     return cmd
 
 
-def parse_shebang_from_file(path):
+def parse_shebang_from_file(path: str) -> Tuple[str, ...]:
     """Parse the shebang given a file path."""
     if not os.path.lexists(path):
-        raise ValueError('{} does not exist.'.format(path))
+        raise ValueError(f'{path} does not exist.')
     if not os.access(path, os.X_OK):
         return ()
 
-    with open(path, 'rb') as f:
-        return parse_shebang(f)
+    try:
+        with open(path, 'rb') as f:
+            return parse_shebang(f)
+    except OSError as e:
+        if e.errno == errno.EINVAL:
+            return ()
+        else:
+            raise
 
 
 COPYRIGHT_RE = re.compile(r'^\s*(Copyright|\(C\)) .*$', re.I | re.MULTILINE)
 WS_RE = re.compile(r'\s+')
 
 
-def _norm_license(s):
+def _norm_license(s: str) -> str:
     s = COPYRIGHT_RE.sub('', s)
     s = WS_RE.sub(' ', s)
     return s.strip()
 
 
-def license_id(filename):
+def license_id(filename: str) -> Optional[str]:
     """Return the spdx id for the license contained in `filename`.  If no
     license is detected, returns `None`.
 
@@ -197,9 +240,9 @@
     3. check exact text match with existing licenses
     4. failing that use edit distance
     """
-    import editdistance  # `pip install identify[license]`
+    import editdistance_s  # `pip install identify[license]`
 
-    with io.open(filename, encoding='UTF-8') as f:
+    with open(filename, encoding='UTF-8') as f:
         contents = f.read()
 
     norm = _norm_license(contents)
@@ -217,7 +260,7 @@
         if norm and abs(len(norm) - len(norm_license)) / len(norm) > .05:
             continue
 
-        edit_dist = editdistance.eval(norm, norm_license)
+        edit_dist = editdistance_s.distance(norm, norm_license)
         if edit_dist < min_edit_dist:
             min_edit_dist = edit_dist
             min_edit_dist_spdx = spdx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/identify/interpreters.py 
new/identify-2.2.10/identify/interpreters.py
--- old/identify-1.4.14/identify/interpreters.py        2020-04-03 
23:34:39.000000000 +0200
+++ new/identify-2.2.10/identify/interpreters.py        2021-06-07 
19:18:24.000000000 +0200
@@ -1,10 +1,12 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 INTERPRETERS = {
+    'ash': {'shell', 'ash'},
+    'awk': {'awk'},
     'bash': {'shell', 'bash'},
+    'bats': {'shell', 'bash', 'bats'},
+    'csh': {'shell', 'csh'},
     'dash': {'shell', 'dash'},
+    'expect': {'expect'},
+    'ksh': {'shell', 'ksh'},
     'node': {'javascript'},
     'nodejs': {'javascript'},
     'perl': {'perl'},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/identify/vendor/licenses.py 
new/identify-2.2.10/identify/vendor/licenses.py
--- old/identify-1.4.14/identify/vendor/licenses.py     2020-04-03 
23:34:39.000000000 +0200
+++ new/identify-2.2.10/identify/vendor/licenses.py     2021-06-07 
19:18:24.000000000 +0200
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
 LICENSES = (
     (
         '0BSD',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/requirements-dev.txt 
new/identify-2.2.10/requirements-dev.txt
--- old/identify-1.4.14/requirements-dev.txt    2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/requirements-dev.txt    2021-06-07 19:18:24.000000000 
+0200
@@ -1,3 +1,3 @@
+covdefaults
 coverage
-pre-commit>=0.12.0
 pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/setup.cfg 
new/identify-2.2.10/setup.cfg
--- old/identify-1.4.14/setup.cfg       2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/setup.cfg       2021-06-07 19:18:24.000000000 +0200
@@ -1,41 +1,57 @@
 [metadata]
 name = identify
-version = 1.4.14
+version = 2.2.10
 description = File identification library for Python
 long_description = file: README.md
 long_description_content_type = text/markdown
-url = https://github.com/chriskuehl/identify
+url = https://github.com/pre-commit/identify
 author = Chris Kuehl
 author_email = cku...@ocf.berkeley.edu
 license = MIT
 license_file = LICENSE
 classifiers =
     License :: OSI Approved :: MIT License
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.4
-    Programming Language :: Python :: 3.5
+    Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
     Programming Language :: Python :: Implementation :: CPython
     Programming Language :: Python :: Implementation :: PyPy
 
 [options]
 packages = find:
-python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
+python_requires = >=3.6.1
+
+[options.packages.find]
+exclude =
+    tests*
+    testing*
 
 [options.entry_points]
 console_scripts =
     identify-cli=identify.cli:main
 
 [options.extras_require]
-license = editdistance
-
-[options.packages.find]
-exclude =
-    tests*
-    testing*
+license =
+    editdistance-s
 
-[wheel]
+[bdist_wheel]
 universal = True
+
+[coverage:run]
+plugins = covdefaults
+
+[mypy]
+check_untyped_defs = true
+disallow_any_generics = true
+disallow_incomplete_defs = true
+disallow_untyped_defs = true
+no_implicit_optional = true
+
+[mypy-testing.*]
+disallow_untyped_defs = false
+
+[mypy-tests.*]
+disallow_untyped_defs = false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/setup.py new/identify-2.2.10/setup.py
--- old/identify-1.4.14/setup.py        2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/setup.py        2021-06-07 19:18:24.000000000 +0200
@@ -1,6 +1,2 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 from setuptools import setup
 setup()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/tests/cli_test.py 
new/identify-2.2.10/tests/cli_test.py
--- old/identify-1.4.14/tests/cli_test.py       2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/tests/cli_test.py       2021-06-07 19:18:24.000000000 
+0200
@@ -1,7 +1,3 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 from identify import cli
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/tests/extensions_test.py 
new/identify-2.2.10/tests/extensions_test.py
--- old/identify-1.4.14/tests/extensions_test.py        2020-04-03 
23:34:39.000000000 +0200
+++ new/identify-2.2.10/tests/extensions_test.py        2021-06-07 
19:18:24.000000000 +0200
@@ -1,7 +1,3 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
 import pytest
 
 from identify import extensions
@@ -13,6 +9,12 @@
     assert len({'text', 'binary'} & tags) == 1, tags
 
 
+@pytest.mark.parametrize('name', extensions.NAMES)
+def test_names_have_binary_or_text(name):
+    tags = extensions.NAMES[name]
+    assert len({'text', 'binary'} & tags) == 1, tags
+
+
 @pytest.mark.parametrize('extension', extensions.EXTENSIONS_NEED_BINARY_CHECK)
 def test_need_binary_check_do_not_specify_text_binary(extension):
     tags = extensions.EXTENSIONS_NEED_BINARY_CHECK[extension]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/tests/identify_test.py 
new/identify-2.2.10/tests/identify_test.py
--- old/identify-1.4.14/tests/identify_test.py  2020-04-03 23:34:39.000000000 
+0200
+++ new/identify-2.2.10/tests/identify_test.py  2021-06-07 19:18:24.000000000 
+0200
@@ -1,10 +1,11 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
+import builtins
+import errno
 import io
 import os
+import socket
 import stat
+from tempfile import TemporaryDirectory
+from unittest import mock
 
 import pytest
 
@@ -14,6 +15,21 @@
 def test_all_tags_includes_basic_ones():
     assert 'file' in identify.ALL_TAGS
     assert 'directory' in identify.ALL_TAGS
+    assert 'executable' in identify.ALL_TAGS
+    assert 'text' in identify.ALL_TAGS
+    assert 'socket' in identify.ALL_TAGS
+
+
+@pytest.mark.parametrize(
+    'tag_group',
+    (
+        identify.TYPE_TAGS,
+        identify.MODE_TAGS,
+        identify.ENCODING_TAGS,
+    ),
+)
+def test_all_tags_contains_all_groups(tag_group):
+    assert tag_group < identify.ALL_TAGS
 
 
 def test_all_tags_contains_each_type():
@@ -41,6 +57,17 @@
     assert identify.tags_from_path(x.strpath) == {'symlink'}
 
 
+def test_tags_from_path_socket():
+    tmproot = '/tmp'  # short path avoids `OSError: AF_UNIX path too long`
+    with TemporaryDirectory(dir=tmproot) as tmpdir:
+        socket_path = os.path.join(tmpdir, 'socket')
+        with socket.socket(socket.AF_UNIX) as sock:
+            sock.bind(socket_path)
+            tags = identify.tags_from_path(socket_path)
+
+    assert tags == {'socket'}
+
+
 def test_tags_from_path_broken_symlink(tmpdir):
     x = tmpdir.join('foo')
     x.mksymlinkto(tmpdir.join('lol'))
@@ -105,7 +132,7 @@
     x = tmpdir.join('t.plist')
     x.write(
         '<?xml version="1.0" encoding="UTF-8"?>\n'
-        '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>\n'
+        '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>\n'  # noqa: E501
         '<plist version="1.0">\n'
         '<dict>\n'
         '\t<key>Last Login Name</key>\n'
@@ -131,6 +158,11 @@
         ('Pipfile.lock', {'text', 'json'}),
         ('mod/test.py', {'text', 'python'}),
         ('mod/Dockerfile', {'text', 'dockerfile'}),
+        ('Gemfile', {'text', 'ruby'}),
+        ('Gemfile.lock', {'text'}),
+        ('Jenkinsfile', {'text', 'groovy', 'jenkins'}),
+        ('build.jenkins', {'text', 'groovy', 'jenkins'}),
+        ('build.jenkinsfile', {'text', 'groovy', 'jenkins'}),
 
         # does not set binary / text
         ('f.plist', {'plist'}),
@@ -177,14 +209,16 @@
     (
         (b'hello world', True),
         (b'', True),
-        ('??????????  ???(?????????)???(????????????)???'.encode('utf8'), 
True),
-        (r'??\_(???)_/??'.encode('utf8'), True),
-        ('??????(???o???)????????? ( ???o???) ????????? ( ) ????????? (???o??? 
) ?????????(???o???)??????'.encode('utf8'), True),
+        ('??????????  ???(?????????)???(????????????)???'.encode(), True),
+        (r'??\_(???)_/??'.encode(), True),
+        ('??????(???o???)????????? ( ???o???) ????????? ( ) ????????? (???o??? 
) ??????'.encode(), True),
         ('????????'.encode('latin1'), True),
 
         (b'hello world\x00', False),
-        (b'\x7f\x45\x4c\x46\x02\x01\x01', False),  # first few bytes of 
/bin/bash
-        (b'\x43\x92\xd9\x0f\xaf\x32\x2c', False),  # some /dev/urandom output
+        # first few bytes of /bin/bash
+        (b'\x7f\x45\x4c\x46\x02\x01\x01', False),
+        # some /dev/urandom output
+        (b'\x43\x92\xd9\x0f\xaf\x32\x2c', False),
     ),
 )
 def test_is_text(data, expected):
@@ -217,6 +251,66 @@
         (b"#!/path'with/quotes    y", ("/path'with/quotes", 'y')),
         # Don't regress on leading/trailing ws
         (b"#! /path'with/quotes y ", ("/path'with/quotes", 'y')),
+        # Test nix-shell specialites with shebang on second line
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#! nix-shell -i bash -p python',
+            ('bash',),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#! nix-shell -i python -p coreutils',
+            ('python',),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#! nix-shell -p coreutils -i python',
+            ('python',),
+        ),
+        # multi-line and no whitespace variation
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#! nix-shell -p coreutils\n'
+            b'#! nix-shell -i python',
+            ('python',),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#!nix-shell -p coreutils\n'
+            b'#!nix-shell -i python',
+            ('python',),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#!\xf9\x93\x01\x42\xcd',
+            ('nix-shell',),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#!\x00\x00\x00\x00',
+            ('nix-shell',),
+        ),
+        # non-proper nix-shell
+        (b'#! /usr/bin/nix-shell', ('/usr/bin/nix-shell',)),
+        (b'#! /usr/bin/env nix-shell', ('nix-shell',)),
+        (
+            b'#! /usr/bin/env nix-shell non-portable-argument',
+            ('nix-shell', 'non-portable-argument'),
+        ),
+        (
+            b'#! /usr/bin/env nix-shell\n'
+            b'#! nix-shell -i',
+            ('nix-shell',),   # guard against index error
+        ),
+        # interpret quotes correctly
+        (
+            b'#!/usr/bin/env nix-shell\n'
+            b'#!nix-shell --argstr x "a -i python3 p"\n'
+            b'#!nix-shell -p hello\n'
+            b'#!nix-shell -i bash\n'
+            b'#!nix-shell --argstr y "b -i runhaskell q"',
+            ('bash',),
+        ),
         (b'\xf9\x93\x01\x42\xcd', ()),
         (b'#!\xf9\x93\x01\x42\xcd', ()),
         (b'#!\x00\x00\x00\x00', ()),
@@ -244,6 +338,15 @@
     assert identify.parse_shebang_from_file(x.strpath) == ('python',)
 
 
+def test_parse_shebang_open_raises_einval(tmpdir):
+    x = tmpdir.join('f')
+    x.write('#!/usr/bin/env not-expected\n')
+    make_executable(x)
+    error = OSError(errno.EINVAL, f'Invalid argument {x}')
+    with mock.patch.object(builtins, 'open', side_effect=error):
+        assert identify.parse_shebang_from_file(x.strpath) == ()
+
+
 def make_executable(filename):
     original_mode = os.stat(filename).st_mode
     os.chmod(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/identify-1.4.14/tox.ini new/identify-2.2.10/tox.ini
--- old/identify-1.4.14/tox.ini 2020-04-03 23:34:39.000000000 +0200
+++ new/identify-2.2.10/tox.ini 2021-06-07 19:18:24.000000000 +0200
@@ -1,6 +1,5 @@
 [tox]
-envlist = py27,py35,py36,pypy
-tox_pip_extensions_ext_venv_update = true
+envlist = py36,pypy3,pre-commit
 
 [testenv]
 deps = -rrequirements-dev.txt
@@ -9,11 +8,11 @@
     coverage erase
     coverage run -m pytest {posargs:tests}
     coverage report --fail-under 100
-    pre-commit install -f --install-hooks
-    pre-commit run --all-files
 
-[flake8]
-max-line-length = 119
+[testenv:pre-commit]
+skip_install = true
+deps = pre-commit
+commands = pre-commit run --all-files --show-diff-on-failure
 
 [pep8]
 ignore = E265,E501,W504

Reply via email to