Skip to content

Automate the creation of requirement.txt and fetch deps - #2118

Merged
pombredanne merged 14 commits into
aboutcode-org:developfrom
Abhishek-Dev09-zz:#295-requirements.txt
Jul 27, 2020
Merged

Automate the creation of requirement.txt and fetch deps#2118
pombredanne merged 14 commits into
aboutcode-org:developfrom
Abhishek-Dev09-zz:#295-requirements.txt

Conversation

@Abhishek-Dev09-zz

@Abhishek-Dev09-zz Abhishek-Dev09-zz commented Jul 20, 2020

Copy link
Copy Markdown

By running this script, we will able to create and update the requirements.txt by providing the input directory like thirdparty .

This script will fetch dependencies with all corresponding files(.whl,.tar.gz,.LICENCE,.NOTICE,.ABOUT) from the given target . This feature will ask ScanCode's developer to provide dependencies as package_name,version and target directory where the built wheels and tarballs would be fetched.
Signed-off-by: Abhishek Kumar abhishek.kasyap09@gmail.com

Fixes aboutcode-org/skeleton#50 #2087

By running this script, we will able to create and update the requirements.txt by providing the input directory like thirdparty . Also adding deps setuptools which is deps of zc.lockfile-2.0

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Identify Python version to extract abi of wheels which helps us in filtering the required deps.

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
This script will fetch dependencies with all corresponding files(.whl,.tar.gz,.LICENCE,.NOTICE,.ABOUT) from the given target . This feature will ask  ScanCode's developer to provide dependencies as package_name,version and target directory where the built wheels and tarballs would be fetched.

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
@Abhishek-Dev09-zz Abhishek-Dev09-zz changed the title Automate the creation of requirement.txt Automate the creation of requirement.txt and fetch deps Jul 21, 2020

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks... see my comments!

Comment thread etc/scripts/freeze_and_update_reqs.py
Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
)
]
if not (os.path.isdir("required_deps")):
os.mkdir("required_deps")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you create that directory?

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 21, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To filter the dependencies of specific python version we want because we have both py2 and py3 wheels in thirdparty. Don't worry it will deleted later by scripts itself.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so please add a comment explaining that... and also this may not be created where you want. Make sure you use a well known location or better use some temp directory instead since this is temporary

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean to say bin

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a temp dir instead

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread etc/scripts/scancode.py
@@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not name this scancode ;) that's confusing!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest the better name.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deps_info.py

Comment thread etc/scripts/scancode.py Outdated
about = [files for files in dependency if files.endswith(".ABOUT")]
notice = [files for files in dependency if files.endswith(".NOTICE")]
license = [files for files in dependency if files.endswith(".LICENSE")]
print(*whl, sep="\n")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you print all that ?

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 21, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because scancode's developer want to fetch the deps in target directory. Script will know developer by printing the info of deps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's too verbose by default. Hide the prints behind an option

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it shows ONLY .ABOUT/.NOTICE/.LICENCE/.whl/.tar.gz . Not too verbose i have seen

@@ -0,0 +1,15 @@
about_resource: setuptools-41.2.0-py2.py3-none-any.whl

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should already have setuptools..... good catch. But please do not commit it there, craft another PR instead just for that.

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 21, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry, i already mentioned in PR description. FYI there is no deps named setuptools . That's why i added wheels setuptools also here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that, but please provide a different PR for adding that back (and FYI zopefoundation/zc.lockfile#22 )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed and PR #2123

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks... please see my comments inline

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"--output-file",
output_file,
"--verbose",
"--upgrade-package",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you do this? we never want to do some unwanted upgrade-package IMHO and what is "package_name", below about?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feature alow you to upgrade specfic package. See help by running this arg.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I known that but what is "package_name" I know of no package whose name is "package_name"
If this is some kind of magic, explain it in comments, do not make me chase down the help of that command

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case why would I want to upgrade a package there? Please elaborate and explain in comments

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package name may be intbitset, banal, urlpy . Anything deps that exist in thirdparty

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated

parser.add_argument(
"--upgrade",
help="Upgrade all dependencies to new version. ",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you have trailing whitespaces here and elsewhere

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"""
Generate a requirement.txt file of all dependencies present in thirdparty.
"""
thirdparty = list(resource_iter(input_dir, with_dirs=False))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list() wrapper is not needed here

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 22, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated

def generate_req_text(input_dir, output_file=False, package_name=False):
"""
Generate a requirement.txt file of all dependencies present in thirdparty.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and what are the args?
this should IMHO be something such as:

Generate a requirement file at `output_file` of all dependencies wheels and sdists present in the `input_dir` directory.
If a `package_name` is provided it will be updated to its latest version.

though I am not sure this is true for package_name
Also output_file=False, package_name=False is weird. These should be None... and output_file should always be required

Also what is the base used there? the setup.py or some requirements.in file? I think we will need a requirements.in file

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Base used here : setup.py and no need of requirements.in file. And by default output_file is requirements.txt and it is default arguments.

Comment thread etc/scripts/scancode.py Outdated
about = [files for files in dependency if files.endswith(".ABOUT")]
notice = [files for files in dependency if files.endswith(".NOTICE")]
license = [files for files in dependency if files.endswith(".LICENSE")]
print(*whl, sep="\n")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's too verbose by default. Hide the prints behind an option

@@ -0,0 +1,15 @@
about_resource: setuptools-41.2.0-py2.py3-none-any.whl

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that, but please provide a different PR for adding that back (and FYI zopefoundation/zc.lockfile#22 )

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks... see my comments

Comment thread etc/scripts/deps_info.py Outdated
Comment thread etc/scripts/deps_info.py Outdated

def main_with_args(args: str) -> None:
parser = argparse.ArgumentParser(
description="""Fetch a specific package with version in given target like thirdparty by default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thsi command seems if fetches nothing at all, does it?

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it description of function , you know this thing by running --help option. I help developer when he put --help option

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be instead:

Search PACKAGE_NAME (with an optional VERSION_OF_PACKAGE) in the TARGET_DIR directory. 
Print results on screen.

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated

def generate_req_text(input_dir, output_file=None, package_name=None):
"""
Generate a requirement file at `output_file`(by default requirements.txt) of all dependencies wheels and sdists present in the `input_dir` directory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap this. Also if you want a default of (by default requirements.txt)... then set the default in the function definition and not as None

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already set as defaults.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By wrap, wrap the very long lines.

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
)
]
if not (os.path.isdir("required_deps")):
os.mkdir("required_deps")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a temp dir instead

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"--output-file",
output_file,
"--verbose",
"--upgrade-package",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I known that but what is "package_name" I know of no package whose name is "package_name"
If this is some kind of magic, explain it in comments, do not make me chase down the help of that command

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"--output-file",
output_file,
"--verbose",
"--upgrade-package",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case why would I want to upgrade a package there? Please elaborate and explain in comments

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"--no-index",
]
)
shutil.rmtree("required_deps")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather you use a temp file with a "with" context manager to avoid leaving dangling files

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a file , it is directory

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated

parser.add_argument(
"--output",
help="Output file name. Required if more than one input file is given. Will be derived from input file otherwise.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid implicit, derived name. It is preferred to always require an input instead

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pip-tools uses --output-file for same purpose why should i not not use --output?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is to avoid using a derived name. Instead make this always required and not implied.

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok , your call i changing the option --output to --requirement . And making always required.

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
tpdir = args.deps_directory
output_file = args.output
package_name = args.upgrade_package
upgrade = args.upgrade or None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This argument is not used at all... so what is it for?

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upgrade is for upgrading all packages whereas upgrade_package is for specific package,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But where do you use it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not an argument used anywhere in your functions

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 23, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch .It is an option just like ON/OFF . It is used here only , i have tested it it works, if you want i will paste output here.

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
"--verbose",
"--allow-unsafe",
"--upgrade-package",
"package_name",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"package_name" is NOT a variable here ... but a plain string. This cannot work as it is... you need to test your code.

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 24, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah it is function parameter through arguments . I have treated like temp dir as That is also also in double quotes but it is dir not variable . Same issue with upgrade parameter also.

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Comment thread etc/scripts/deps_info.py Outdated
parser = argparse.ArgumentParser(
description="""Fetch a specific package with version in given target like thirdparty by default.
EXAMPLE:
scancode.py \\

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deps

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my nitpickings inline for your review!
Thanks you for your persistence!

Comment thread etc/scripts/deps_info.py Outdated
import sys


def search_package(package_name, target, version):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please version=None since this is optional

Comment thread etc/scripts/deps_info.py
import argparse
import fnmatch
from commoncode.fileutils import resource_iter
import sys

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort imports

Comment thread etc/scripts/deps_info.py Outdated

def search_package(package_name, target, version):
"""
Search specific package in given directory with all corresponding files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use instead:

Search `package_name` (with an optional `version`) in the `target` directory. Print results on screen.

Comment thread etc/scripts/deps_info.py Outdated

def main_with_args(args: str) -> None:
parser = argparse.ArgumentParser(
description="""Fetch a specific package with version in given target like thirdparty by default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be instead:

Search PACKAGE_NAME (with an optional VERSION_OF_PACKAGE) in the TARGET_DIR directory. 
Print results on screen.

Comment thread etc/scripts/deps_info.py Outdated

parser.add_argument(
"--target",
help=" a target directory where the built wheels and tarballs would be fetched.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this:
"Directory to search for package wheels and tarballs. [default: thirdparty]"

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated

def generate_req_text(input_dir, output_file=None, package_name=None):
"""
Generate a requirement file at `output_file`(by default requirements.txt) of all dependencies wheels and sdists present in the `input_dir` directory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By wrap, wrap the very long lines.

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
'pip-compile',
'--generate-hashes',
'--find-links',
'temp dir',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
if package_name:
pip_args.extend(['--upgrade-package', package_name])
run(pip_args)
rmtree('temp dir')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a proper https://docs.python.org/3/library/tempfile.html?highlight=tempfile#module-tempfile you will NOT need to rm anything, with will be handled for you if you use a context manager.
such as this example from the Python doc:

# create a temporary directory using the context manager
>>> with tempfile.TemporaryDirectory() as tmpdirname:
...     print('created temporary directory', tmpdirname)
 .... do your things here

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
--deps_directory DEPS_DIRECTORY \\
--output OUTPUT \\
--upgrade_package PACKAGE_NAME \\
""",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this example.

package_name = args.upgrade_package
upgrade = args.upgrade or False
generate_req_text(tpdir, requirement_file, package_name, upgrade)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer named keyword arguments for example:
(tpdir=tpdir, requirement_file=requirement_file, package_name=package_name, upgrade=upgrade) But do not use these names... use the same variable names on both sides: e.g. if you use args.deps_directory then usedeps_directoryand nottpdir`

Comment thread etc/scripts/freeze_and_update_reqs.py
Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
from fnmatch import fnmatchcase
import os
from subprocess import run
from shutil import copy, rmtree

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: your imports are not sorted. Try to use https://pypi.org/project/isort/

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 26, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh , i missed that .Also i have to remove unused import

Comment thread etc/scripts/freeze_and_update_reqs.py Outdated
def generate_req_text(find_links, req_file, package_name=None, upgrade=False):
"""
Generate a requirement file at `req_file` of all dependencies wheels and
sdists present in the `input_dir` directory.If a `package_name` is provided

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no input_dir?
...sdists present in the input_dir directory...
Do you mind doing an extra review pass on this PR and #2117 to make sure the docstrings are well synced with the actual function arguments and what the function does>

@Abhishek-Dev09-zz Abhishek-Dev09-zz Jul 26, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, this PR has reviewed many times. I would like work on diff PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Signed-off-by: Abhishek Kumar <abhishek.kasyap09@gmail.com>
Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking fine. Thank you! merging

@pombredanne
pombredanne merged commit 7036274 into aboutcode-org:develop Jul 27, 2020
@Abhishek-Dev09-zz
Abhishek-Dev09-zz deleted the #295-requirements.txt branch July 27, 2020 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dev utility: Create script to generate requirements with hashes

3 participants