Hello 👋🏿!
I am Hussein Mukhtar, a Senior Computer Science student in Suez University, And I'd like to walk you through Artec
.
Three years ago, I started learning Python and It was a good "hobby", Till you want to share your works with people.
Everything gets very complicated, "How do you share the code?" & "Why is this a single file not module?" & "How come this is not a package?", you name it. 😒
Also in that time I discovered linux and it's terminal tools, Everything you want to do you can do it from the terminal with a tap of your finger.
So I wanted to automate the basic process of starting a new project for me like ng new
or flutter create
, Also use this chance to hone my skills.
Artec was the brainchild of that thought.
Simply put, Artec takes a specific configuration you provide or uses the default structure to create the project (I prefer to call it repo), It also helps you setup your license, your README.md and so on.
When you encounter a problem, it is often helpful to first search for existing solutions, and that I did.
The first thing I encountered was cookiecutter a really great tool (Too great for a novice), So I moved on till I found this beauty here, It works and does great part of what I want but nothing big just a couple of tweaks here and there and It will work (eventually It was more than couple of tweaks but meh.) or though I thought.
Well, It was bigger than I imagined and needed more work, and I kinda felt like I am gonna enjoy making this, So here we are.
Starting a repo knowing full well you won't use it again is completely different than having high hopes for one, that makes it special to you.
So I started by porting what I may use from PyBoiler, long story short It needed some heavy lifting.
The first thing I focused on was parsing arguments to the program, for that I made a simple wrapper for argparse in the file parser.py.
The main focus in that wrapper was to make it easy to modify the args whether to add or remove, Theoretically the parser should be "elegant" enough to be recycled in any other project with no hassle, In the end there's a driver function that's easy to use called (main_args).
Couple of things I had to focus on that messed up my code a little bit:
- Custom Action to list my templates.
- Mutually exclusive arguments
Not the easiest part but not the hardest also, It had to accept arguments from our parser then decide some things :
- Did you use a template ?
-
Yes :
- Is the template valid ?
- Yes : Use it.
- No : Use default Python structure.
- Is the template valid ?
-
No :
- Is Source provided ?
- Yes : Is valid ?
- Yes : Apply it.
- No : Use default Python structure.
- No : Use default Python structure.
- Yes : Is valid ?
- Is Source provided ?
-
- Did user choose to initialize a git repository ?
- Yes : initialize it.
- No : ignore.
Also, a major key take for me was Exceptions, I kind of ignored raising them or explaining why this exceptions happens to the user and it just leaves them lost in the application.
Although it's a rough implementation, Now I raise specific custom-made exceptions in essential places to help the user and also log the process correctly.
The build method is fairly simple, It just iterates over the structure dictionary and creates each folder and/or file.
The tests was an uncharted waters for me, So trying unittest was probably a good idea. You should have a look here not the best but good enough for me.
The hardest part also the one I learned in the most, let's start with some key takes :
__init__.py
is a very important reserved key file, It's main usage comes when a package provide an API (It isn't necessary here, except in tests), I used it as a connector of the logger module Don't think it's correct but meh.- The project structure might look similar to what I did here (Also The
__main__.py
part isn't 100% perfect):
.
├── artec
│ ├── __main__.py
│ ├── argparser.py
│ ├── boiler.py
│ ├── exceptions.py
│ ├── repo.py
│ └── templates.py
├── CONTRIBUTING.md
├── LEARN.md
├── LICENSE
├── pyproject.toml
├── README.md
├── setup.py
└── test
├── __init__.py
├── test_boiler.py
├── test_exceptions.py
└── test_parser.py
- P.S.: It's not necessary to make the same, some try different structures and it works for them so don't limit yourself to mine.
- I figured that keeping your entry points in
__main__.py
makes it easier for people to figure out where is the start of your project, how does it work, etc. - Be Aware of relative and absolute imports. They are a mess in packaging if your structure isn't "clean" enough.
- Automate your build & deploy, It sucks having to manage the versions and manage uploading them in order each time.
- This is a very good reference.
I am really enjoying this & I hope you enjoy and learn too.