Categories
JavaScript Vue

More Vue Data Grid Components that are Easy to Use

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at some Vue data grid libraries so we can avoid creating them from scratch ourselves.

vue-floatThead

vue-floatThead is a library that lets us create tables with a few options.

We can install it as follows:

npm install vue-floatthead

Then we can use it as follows:

main.js :

import Vue from "vue";  
import App from "./App.vue";  
import FloatThead from "vue-floatthead";  
Vue.use(FloatThead);  
Vue.config.productionTip = false;new Vue({  
  render: h => h(App)  
}).$mount("#app");

App.vue :

<template>  
  <div id="app">  
    <float-thead-table>  
      <thead>  
        <tr>  
          <th>  
            <a href="#">First Name</a>  
          </th>  
          <th>  
            <a href="#">Last Name</a>  
          </th>  
        </tr>  
      </thead>  
      <tbody>  
        <tr v-for='p of persons' :key='p'>  
          <td>{{p.firstName}}</td>  
          <td>{{p.lastName}}</td>           
        </tr>  
      </tbody>  
    </float-thead-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      persons: [  
        { firstName: "Jane", lastName: "Smith" },  
        { firstName: "Alex", lastName: "Smith" }  
      ]  
    };  
  }  
};  
</script>

We registered the component in main.js , then we use the float-thead-table component to build the table.

vue-good-table

vue-good-table is a table library with lots of options. It’s also easy to make a table with filtering and sorting with it.

To install it, we run:

npm install --save vue-good-table

Then to use it, we write:

main.js :

import Vue from "vue";  
import App from "./App.vue";  
import VueGoodTablePlugin from "vue-good-table";  
import "vue-good-table/dist/vue-good-table.css";

Vue.use(VueGoodTablePlugin);  
Vue.config.productionTip = false;

new Vue({  
  render: h => h(App)  
}).$mount("#app");

App.vue :

<template>  
  <div id="app">  
    <input type="text" v-model="searchTerm">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
    ></vue-good-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true  
        }  
      ],  
      rows: [{ name: "Jane" }, { name: "Alex" }]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

We registered the component with Vue.use and imported the styles, then we created the rows and columns data which are passed straight into the vue-good-table as props.

Also, we added the search-options prop to let us pass in the value of the input as the search value. It’s smart enough to search all columns without adding additional code.

Adding pagination is also very easy. To do this, we write:

<template>  
  <div id="app">  
    <input type="text" v-model="searchTerm">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
      :pagination-options="{  
        enabled: true,  
        mode: 'records',  
        perPage: 5,  
        position: 'top',  
        perPageDropdown: [3, 7, 9],  
        dropdownAllowAll: false,  
        setCurrentPage: 2,  
        nextLabel: 'next',  
        prevLabel: 'prev',  
        rowsPerPageLabel: 'Rows per page',  
        ofLabel: 'of',  
        pageLabel: 'page',   
        allLabel: 'All',  
      }"  
    ></vue-good-table>  
  </div>  
</template><script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true  
        }  
      ],  
      rows: [  
        { name: "Jane" },  
        { name: "Alex" },  
        { name: "James" },  
        { name: "Joe" },  
        { name: "Bob" },  
        { name: "Mary" }  
      ]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

All we did is pass some pagination options into the pagination-options props. The object we set as the value of the prop includes options for labels, text for the next and previous page buttons, the drop-down for the number of items to display on the table at one time, and more.

It also has a per-column filter feature which we can add easily by changing the column options as follows:

<template>  
  <div id="app">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
    ></vue-good-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true,  
          filterOptions: {  
            enabled: true,  
            placeholder: "Filter Name",  
            filterValue: "",  
            filterDropdownItems: [],  
            filterFn: this.columnFilterFn,  
            trigger: "enter"  
          }  
        }  
      \],  
      rows: \[  
        { name: "Jane" },  
        { name: "Alex" },  
        { name: "James" },  
        { name: "Joe" },  
        { name: "Bob" },  
        { name: "Mary" }  
      ]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

All we added was the follow property to the column entry:

filterOptions: {  
  enabled: true,  
  placeholder: "Filter Name",  
  filterValue: "",  
  filterDropdownItems: [],  
  filterFn: this.columnFilterFn,  
  trigger: "enter"  
}

to enable filtering for the column.

Conclusion

vue-floatThead is a basic table component to let us build a table. On the other hand, vue-good-table is a full-featured table component that has sorting, filtering, pagination right out of the box. It’s also very easy to add those features to our tables.

Categories
Python

Validating Python Inputs with PyInputPlus

Python is a convenient language that’s often used for scripting, data science, and web development.

In this article, we’ll look at how to validating Python inputs with the PyInputPlus.

Validation Inputs

We use the PyInputPlus package to validate inputs from retrieved from the command line.

To use it, we have to install it. We run pip install pyinputplus to install the package.

Then we can use the following functions in the module to validate inputs:

  • inputStr — it’s like input but we can validate custom validations into it.
  • inputNum — ensures user enters a number and returns an int or float depending on if the number has a decimal point or not
  • inputChoice — ensures user enters of one the provided choices
  • inputMenu — it’s like inputChoice but provides a menu with number or lettered options
  • inputDatetime — ensures user enter a date and time
  • inputYesNo — ensures user enters yes or no
  • inputBool — ensures user enters True or False
  • inputEmail — ensures user enters email address
  • inputFilePath — checks that a user enters a file path
  • inputPassword — like input , but displays * in place of whatever is entered

We can use the module as follows:

import pyinputplus  
print('What is your age?')  
age = pyinputplus.inputNum()  
print('Your age is', age)

The code above asks user to enter their age. If they enter their age, then we display the last line.

Otherwise, we display an error message until they enter a number.

We can pass in the prompt text to the function. For instance, we can write:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?')  
print('Your age is', age)

It works the same way as before except the 'What is your age?’ message doesn’t add a new line.

The min, max, greaterThan, and lessThan Keyword Arguments

We can check if the number entered is in the range we want with min , max , greaterThan , and lessThan keywords.

They do as their names suggest. For instance:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?',  min=0)  
print('Your age is', age)

The code above will check if a number 0 or bigger is entered. If we enter an invalid number, we’ll get an error message until we enter a valid number.

The blank Keyword Argument

We can disallow blank inputs with by passing in a boolean argument for the blank parameter.

For example, we can write:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?',  min=0, blank=False)  
print('Your age is', age)

Then we get Blank values are not allowed. error if we entered a blank value. We can’t proceed until we enter a valid number.

The limit, timeout, and default Keyword Arguments

PyInputPlus functions will continue to ask the same question until we enter a valid value.

To change this, we can use pass in an argument for the limit parameter to limit the number of tries allowed.

For instance, we can write:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?',  min=0, limit=2)  
print('Your age is', age)

to limit the number of tries for answer the 'What is your age?' question to 2.

When we don’t enter a valid number after 2 tries, we get an error.

To set a default value, we can pass in an argument to the default parameter. For instance, we can write:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?',  min=0, default='0', limit=2)  
print('Your age is', age)

When running the code above, if we didn’t enter a valid number after 2 tries, then it’ll print 'Your age is 0' on the screen since we set the default value to 0.

We can set the timeout parameter to limit the time that our program waits for an input to be entered.

For example, we can write:

import pyinputplus  
age = pyinputplus.inputNum(prompt='What is your age?',  timeout=1)  
print('Your age is', age)

After waiting for a second, we’ll get a TimeoutException thrown if nothing is entered.

The allowRegexes and blockRegexes Keyword Arguments

We can set a list of regex strings to the allowRegexes parameter to the PyInputPlus functions.

For example, if we want to make sure the user enters a phone number, we can write:

import pyinputplus  
phone = pyinputplus.inputNum(prompt='What is your phone?',  allowRegexes=[r'\d{3}-\d{3}-\d{4}', r'None'])  
print('Your phone is', phone)

In the code above, we allow phone numbers to be entered as the input value by setting a list of regex with the phone number regex to it.

Then we have to enter a phone number or 'None' before we can proceed.

Conclusion

We can use the PyInputPlus package to validate command line input values.

It has functions to checking various kinds of inputs like numbers, emails, date and time, yes or no, and so on.

Also, we can limit the range of the values that are entered for numbers and so check against regexes so that anything can be checked for the given format.

Categories
Python

Custom Input Validation Python Inputs with PyInputPlus

ython is a convenient language that’s often used for scripting, data science, and web development.

In this article, we’ll look at how to do custom input validation with PyInputPlus.

Passing a Custom Validation Function to inputCustom()

We can use the inputCustom function to validate any input by users,

It accepts a single string argument of what the user entered, raises an exception if the string fails validation, returns None if inputCustom should return the string unchanged, and returns non-None values if inputCustom should return a different string from the one that’s entered.

The function is passed in as the first argument to inputCustom .

For instance, we can use it as follows:

import pyinputplus  
import re  
def check_phone(phone):    
  if bool(re.match(r'\d{3}-\d{3}-\d{4}', phone)) == False:  
    raise Exception('Invalid phone number')  
  return phoneprint('What is your phone number?')  
phone_num = pyinputplus.inputCustom(check_phone)  
print('Your number is', phone_num)

In the code above, we defined the check_phone function, which checks if the entered phone number is a valid phone number or not. If it isn’t, then it raises an exception.

Otherwise, we return the phone number.

Then we pass in the check_phone function to the inputCustom function.

When we run the program, then we can’t get past the prompt until we entered a valid phone number.

Otherwise, we get an error.

Whatever we return in check_phone is returned by inputCustom if validation succeeds.

Creating a Menu with inputMenu

We can use the inputMenu function to create a simple menu. It takes a list of options as strings. Also, we can set the lettered option to add letters to our choices if set to True . We can add numbers to our menu by setting the numbered option to False .

For instance, we can write the following to create a simple menu:

import pyinputplusfruit = pyinputplus.inputMenu(['apple', 'banana', 'orange'], lettered=True, numbered=False)  
print('Chosen fruit', fruit)

Then we can type in a letter to make a choice.

Narrowing Choices with inputChoice

We can use the inputChoice function to allow users to enter a value. The only valid inputs are the choices that we set.

For instance, we can write:

import pyinputplusfruit = pyinputplus.inputChoice(\['apple', 'banana', 'orange'\])  
print('Chosen fruit', fruit)

Then we get:

Please select one of: apple, banana, orange

displayed on the screen.

Once we entered one of the answers listed above, we can proceed.

Conclusion

We can use the inputCustom function to validate any input we want. It takes a validation function as an argument.

The function we pass in takes the input value as a parameter.

It should raise an exception if the input fails validation. Otherwise, it should return the value that’s entered or something derived from it.

inputCustom returns whatever it’s returned with the validation function.

We can create a menu with the inputMenu function and create an input that only accepts a few choices with the inputChoice function.

Categories
Python

Manipulating File Paths with Python

Python is a convenient language that’s often used for scripting, data science, and web development.

In this article, we’ll look at how to read and write files with Python.

Files and File Paths

A file has a filename to reference the file. It also has a path to locate the file’s location.

The path consists of the folder, they can be nested and they form the path.

Backslash on Windows and Forward Slash on macOS and Linux

In Windows, the path consists of backslashes. In many other operating systems like macOS and Linux, the path consists of forward slashes.

Python’s standard pathlib library knows the difference and can sort them out accordingly. Therefore, we should use it to construct paths so that our program will run everywhere.

For instance, we can import pathlib as follows and create a Path object as follows:

from pathlib import Path  
path = Path('foo', 'bar', 'foo.txt')

After running the code, path should be a Path object like the following if we’re running the program above on Linux or macOS:

PosixPath('foo/bar/foo.txt')

If we’re running the code above on Windows, we’ll get a WindowsPath object instead of a PosixPath object.

Using the / Operator to Join Paths

We can use the / operator to join paths. For instance, we can rewrite the path we had into the following code:

from pathlib import Path  
path = Path('foo')/'bar'/'foo.txt'

Then we get the same result as before.

This will also work on Windows, macOS, and Linux since Python will sort out the path accordingly.

What we shouldn’t use is the string’s join method because the path separator is different between Windows and other operating systems.

For instance:

path = '/'.join(['foo', 'bar', 'foo.txt'])

isn’t going to work on Windows since the path has forward slash.

The Current Working Directory

We can get the current working directory (CWD), which is the directory the program is running on.

We can change the CWD with the os.chdir function and get the current CWD with the Path.cwd function.

For instance, we can write:

from pathlib import Path  
import os  
print(Path.cwd())  
os.chdir(Path('foo')/'bar')  
print(Path.cwd())

Then we get:

/home/runner/AgonizingBasicSpecialist  
/home/runner/AgonizingBasicSpecialist/foo/bar

as the output.

As we can see, chdir changed the current working directory, so that we can use manipulate files in directories other than the ones that the program is running in.

The Home Directory

The home directory is the root directory of the profile folder of the user’s user account.

For instance, we can write the following:

from pathlib import Path  
path = Path.home()

Then the value of path is something likePosixPath(‘/home/runner’) .

Absolute vs. Relative Paths

An absolute path is a path that always begins with the root folder. A relative is a path that’s relative to the program’s current working directory.

For example, on Windows, C:\Windows is an absolute path. A relative path is something like .\foo\bar . It starts with a dot and foo is inside the current working directory.

Creating New Folders Using the os.makedirs() Function

We can make a new folder with the os.makedirs function.

For instance, we can write:

from pathlib import Path  
Path(Path.cwd()/'foo').mkdir()

Then we make a foo directory inside our current working directory.

Handling Absolute and Relative Paths

We can check if a path is an absolute path with the is_absolute method.

For instance, we can write:

from pathlib import Path  
is_absolute = Path.cwd().is_absolute()

Then we should see is_absolute being True since Path.cwd() returns an absolute path.

We can call os.path.abspath to returns a string with of the absolute path of the path argument that we pass in.

For instance, given that we have the directory foo in the current working directory, we can write:

from pathlib import Path  
import os  
path = os.path.abspath(Path('./foo'))

to get the absolute path of the foo folder.

We then should get something like:

'/home/runner/AgonizingBasicSpecialist/foo'

as the value of path .

os.path.isabs(path) is a method that returns True is a path that is absolute.

The os.path.relpath(path, start) method will return a string of the relative path from the start path to path .

If start isn’t provided, then the current working directory is used as the start path.

For instance, if we have the folder /foo/bar in our home directory, then we can get the path of ./foo/bar relative to the home directory by writing:

from pathlib import Path  
import os  
path = os.path.relpath(Path.home(), Path('./foo')/'bar')

Then the path has the value ‘../../..’ .

Conclusion

We can use the path and os modules to construct and manipulate paths.

Also, we can also use the / with Path objects to create a path that works with all operating systems.

We can also path in paths to the Path function to construct paths.

Python also has methods to check for relative and absolute paths and the os module can construct relative paths from 2 absolute paths.

Categories
Python

Using Regex with Python

Python is a convenient language that’s often used for scripting, data science, and web development.

In this article, we’ll look at how to use regex with Python to make finding text easier.

Finding Patterns of Text with Regular Expressions

Regular expressions, or regexes, are descriptions for a pattern of text.

For instance, \d represents a single digit. We can combine characters to create regexes to search text.

To use regexes to search for text, we have to import the re module and then create a regex object with a regex string as follows:

import re  
phone_regex = re.compile('\d{3}-\d{3}-\d{4}')

The code above has the regex to search for a North American phone number.

Then if we have the following string:

msg = 'Joe\'s phone number is 555-555-1212'

We can look for the phone number inside msg with the regex object’s search method as follows:

import re  
phone_regex = re.compile('\d{3}-\d{3}-\d{4}')  
msg = 'Joe\'s phone number is 555-555-1212'  
match = phone_regex.search(msg)

When we inspect the match object, we see something like:

<re.Match object; span=(22, 34), match='555-555-1212'>

Then we can return a string representation of the match by calling the group method:

phone = match.group()

phone has the value '555-555-1212' .

Grouping with Parentheses

We can use parentheses to group different parts of the result into its own match entry.

To do that with our phone number regex, we can write:

phone_regex = re.compile('(\d{3})-(\d{3})-(\d{4})')

Then when we call search , we can either get the whole search string, or individual match groups.

group takes an integer that lets us get the parts that are matched by the groups.

Therefore, we can rewrite our program to get the whole match and the individual parts of the phone number as follows:

import re  
phone_regex = re.compile('(\d{3})-(\d{3})-(\d{4})')  
msg = 'Joe\'s phone number is 123-456-7890'  
match = phone_regex.search(msg)  
phone = match.group()  
area_code = match.group(1)  
exchange_code = match.group(2)  
station_code = match.group(3)

In the code above, phone should be ‘123–456–7890’ since we passed in nothing to group. Passing in 0 also returns the same thing.

area_code should be '123' since we passed in 1 to group , which returns the first group match.

exchange_code should be '456' since we passed in 2 to group , which returns the 2nd group match.

Finally, station_code should be '7890' since we passed in 3 to group , which returns the 3rd group match.

If we want to pass in parentheses or any other special character as a character of the pattern rather than a symbol for the regex, then we have to put a \ before it.

Matching Multiple Groups with the Pipe

We can use the | symbol, which is called a pipe to match one of many expressions.

For instance, we write the following to get the match:

import re  
name_regex = re.compile('Jane|Joe')  
msg = 'Jane and Joe'  
match = name_regex.search(msg)  
match = match.group()

match should be 'Jane' since this is the first match that’s found according to the regex.

We can combine pipes and parentheses to find a part of a string. For example, we can write the following code:

import re  
snow_regex = re.compile(r'snow(man|mobile|shoe)')  
msg = 'I am walking on a snowshoe'  
snow_match = snow_regex.search(msg)  
match = snow_match.group()  
group_match = snow_match.group(1)

to get the whole match with match , which has the value 'snowshoe' .

group_match should have the partial group match, which is 'shoe' .

Optional Matching with the Question Mark

We can add a question mark to the end of a group, which makes the group optional for matching purposes.

For example, we can write:

import re  
snow_regex = re.compile(r'snow(shoe)?')  
msg = 'I am walking on a snowshoe'  
msg_2 = 'I am walking on snow'  
snow_match = snow_regex.search(msg)  
snow_match_2 = snow_regex.search(msg_2)

Then snow_match.group() returns 'snowshoe' and snow_match.group(1) returns 'shoe' .

Since the (shoe) group is optional, snow_match_2.group() returns 'snow' and snow_match_2.group(1) returns None .

Conclusion

We can use regexes to find patterns in strings. They’re denoted by a set of characters that defines a pattern.

In Python, we can use the re module to create a regex object from a string.

Then we can use it to do searches with the search method.

We can define groups with parentheses. Once we did that, we can call group on the match object returned by search .

The group is returned when we pass in an integer to get it by their position.

We can make groups optional with a question mark appended after the group.